From c8e6f30a27d112befcaf716bf1db57a3560f1c4d Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 14 Sep 2026 11:05:39 +0200 Subject: [PATCH] =?UTF-8?q?Basis:=20Certvia=20dev@a48c5fb=20als=20Fundamen?= =?UTF-8?q?t=20f=C3=BCr=20Craftvia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 --- .claude/launch.json | 11 + .dockerignore | 12 + .env.coolify.example | 72 + .env.example | 90 + .env.prod.example | 76 + .gitea/workflows/ci.yml | 116 + .github/workflows/ci.yml | 113 + .gitignore | 47 + AGENTS.md | 40 + CLAUDE.md | 1 + Dockerfile | 121 + README.md | 42 + components.json | 25 + deploy/garage.toml | 34 + docker-compose.coolify.prebuilt.yml | 460 + docker-compose.coolify.yml | 470 + docker-compose.yml | 127 + docs/BRANDING-CERTVIA.md | 149 + docs/DEPLOY-COOLIFY.md | 123 + docs/DEPLOY-PROD-CONTABO.md | 485 + docs/DEPLOY-PROD-PREBUILT.md | 82 + docs/DEVOPS-INTEGRATION-RUNBOOK.md | 119 + docs/FEINDESIGN-framework-assessment.md | 290 + docs/FEINDESIGN-identity-mandanten.md | 219 + docs/FRAMEWORK-MAPPING-ISO27001.md | 150 + docs/HANDBUCH-KUNDENBETREUUNG.md | 83 + docs/HANDOVER-DEV.md | 197 + docs/HANDOVER-DEVOPS.md | 122 + docs/HANDOVER-PM.md | 98 + docs/IMPL-tisax-wizard-neustruktur.md | 238 + docs/ISMS-Abhaengigkeitskarte-GEFIM.html | 244 + docs/ISMS-GUI-Verbesserungen-GEFIM.html | 382 + docs/ISMS-Lieferantenmanagement-GEFIM.html | 393 + docs/ISMS-Prototyp-GEFIM.html | 753 + docs/KONZEPT-backup-restore.md | 135 + docs/KONZEPT-backup-target.md | 57 + docs/KONZEPT-framework-iso27001.md | 162 + docs/KONZEPT-garage-migration.md | 217 + docs/KONZEPT-haertung.md | 50 + docs/KONZEPT-identity-mandanten.md | 98 + docs/KONZEPT-incidents.md | 121 + docs/KONZEPT-ui-i18n.md | 50 + docs/MOCKUP-bia-prozessuebersicht.html | 355 + docs/ONBOARDING-AGENT.md | 67 + docs/PROMPT-lane-backup-target.md | 59 + docs/PROMPT-lane-backup.md | 57 + docs/PROMPT-lane-framework-assessment.md | 120 + docs/PROMPT-lane-framework-iso27001.md | 151 + docs/PROMPT-lane-garage-abnahme.md | 42 + docs/PROMPT-lane-garage-code.md | 36 + docs/PROMPT-lane-garage-infra.md | 35 + docs/PROMPT-lane-garage-provision.md | 37 + docs/PROMPT-lane-haertung.md | 55 + docs/PROMPT-lane-ui-i18n.md | 58 + docs/PROMPT-uebergabe-identity-mandanten.md | 71 + docs/PROMPT-uebergabe-kundenbetreuung.md | 43 + docs/SEC1-MAIL.md | 177 + docs/SEC2-AUTH-SELFSERVICE.md | 154 + docs/SECRETS-REGISTER.md | 78 + docs/SPEC.md | 310 + docs/STAND-dev-branch.md | 404 + docs/UEBERGABE-framework-iso27001.md | 328 + docs/UEBERGABE-identity-mandanten.md | 38 + .../Aufgabenpaket-Branding-Certvia.md | 107 + docs/branding/README-Logo.md | 29 + docs/craftvia/BRANDBOOK.md | 797 + docs/craftvia/SPEC-CRAFTVIA.md | 2480 +++ .../assets/craftvia-brand-identity-v1.png | Bin 0 -> 1303800 bytes docs/reviews/richtlinien-gap-report.md | 323 + ...Aufgabenpaket-Sicherheit-Administration.md | 78 + docs/sicherheit/README.md | 19 + docs/sicherheit/SEC1-Mail-Fundament-Detail.md | 125 + .../SEC2-Auth-SelfService-Detail.md | 100 + .../Sicherheit-und-Administration-Konzept.md | 105 + .../Contracts-Checkliste-Kickoff.md | 168 + .../Paket-DevA-Wizard-Scoping.md | 82 + .../Paket-DevB-Engines-Richtlinien.md | 100 + .../Berater-Anweisung-Fachcontent.md | 68 + .../Onboarding-Wizard-Machbarkeitsanalyse.md | 120 + .../01_Planung/Wizard-Entwickler-Backlog.md | 133 + .../01_Planung/Wizard-Stories.md | 174 + .../C0_README-Fachcontent-Uebersicht.md | 35 + .../C1_Scoping-AL-Pruefziel.md | 444 + .../C2_Fragenkatalog-Wirkung.md | 110 + .../C3_Vorlagen-Annotation.md | 49 + .../02_Fachcontent_C1-C9/C4_Risikokatalog.md | 169 + .../02_Fachcontent_C1-C9/C5_Reifegradlogik.md | 199 + .../C6_Umsetzungshinweise.md | 3778 ++++ .../C7_Rollen-Funktionstrennung.md | 61 + .../C8_Priorisierung-Gap.md | 37 + .../C9_Auswertung-Export.md | 49 + .../Onboarding_Wizard_Fahrplan_Detail.md | 233 + .../03_Referenz/STAND-dev-branch.HINWEIS.md | 9 + docs/wizard-uebergabe/README.md | 20 + eslint.config.mjs | 18 + messages/de.json | 1136 ++ messages/en.json | 1136 ++ next.config.ts | 61 + package-lock.json | 15800 ++++++++++++++++ package.json | 75 + postcss.config.mjs | 7 + prisma.config.ts | 13 + prisma/import-hints.ts | 82 + prisma/import-managed.ts | 222 + prisma/import-policies.ts | 521 + prisma/import-process-catalog.ts | 256 + prisma/import-risks.ts | 63 + .../20260702095800_init/migration.sql | 131 + .../migration.sql | 36 + .../20260702101647_assets_bia/migration.sql | 132 + .../migration.sql | 18 + .../migration.sql | 74 + .../20260702133003_rls_risks/migration.sql | 9 + .../20260702135246_measures/migration.sql | 59 + .../20260702135301_rls_measures/migration.sql | 9 + .../migration.sql | 32 + .../20260703081059_suppliers/migration.sql | 260 + .../migration.sql | 16 + .../migration.sql | 239 + .../20260707132008_policies/migration.sql | 136 + .../migration.sql | 156 + .../migration.sql | 5 + .../migration.sql | 3 + .../migration.sql | 78 + .../migration.sql | 46 + .../migration.sql | 6 + .../migration.sql | 22 + .../20260722092625_tasks/migration.sql | 56 + .../migration.sql | 9 + .../migration.sql | 55 + .../migration.sql | 91 + .../migration.sql | 6 + .../migration.sql | 32 + .../migration.sql | 12 + .../20260728122213_wizard_facts/migration.sql | 29 + .../20260728153225_wizard_scope/migration.sql | 30 + .../migration.sql | 25 + .../migration.sql | 27 + .../20260729101027_risk_catalog/migration.sql | 28 + .../migration.sql | 5 + .../migration.sql | 35 + .../migration.sql | 3 + .../migration.sql | 36 + .../migration.sql | 9 + .../20260730160000_rls_enforce/migration.sql | 391 + .../migration.sql | 14 + .../migration.sql | 84 + .../migration.sql | 57 + .../migration.sql | 38 + .../migration.sql | 15 + .../migration.sql | 3 + .../migration.sql | 136 + .../migration.sql | 18 + .../migration.sql | 18 + .../migration.sql | 3 + .../migration.sql | 94 + .../migration.sql | 3 + .../migration.sql | 158 + .../migration.sql | 54 + .../migration.sql | 35 + .../migration.sql | 20 + .../migration.sql | 12 + .../migration.sql | 40 + .../20260812100000_backup_jobs/migration.sql | 28 + .../migration.sql | 13 + .../20260817130000_incidents/migration.sql | 246 + .../migration.sql | 43 + .../migration.sql | 67 + .../migration.sql | 67 + .../20260821100000_soa_entries/migration.sql | 37 + .../20260821110000_mgmt_clauses/migration.sql | 175 + .../20260821120000_doc_control/migration.sql | 68 + .../migration.sql | 35 + prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 2522 +++ prisma/seed-content.ts | 60 + prisma/seed.ts | 739 + prisma/template-store.ts | 205 + public/assets/logo/certvia-favicon.svg | 5 + .../logo/certvia-lockup-positiv-1024.png | Bin 0 -> 22486 bytes public/assets/logo/certvia-lockup-positiv.svg | 34 + public/assets/logo/certvia-mark-anthrazit.svg | 4 + public/assets/logo/certvia-mark-grau.svg | 4 + .../assets/logo/certvia-mark-negativ-512.png | Bin 0 -> 11220 bytes public/assets/logo/certvia-mark-negativ.svg | 4 + .../assets/logo/certvia-mark-positiv-512.png | Bin 0 -> 13989 bytes public/assets/logo/certvia-mark-positiv.svg | 4 + public/assets/logo/gefim-logo.png | Bin 0 -> 40645 bytes public/favicon.ico | Bin 0 -> 576 bytes public/favicon/apple-touch-icon-180.png | Bin 0 -> 6766 bytes public/favicon/icon-16.png | Bin 0 -> 572 bytes public/favicon/icon-32.png | Bin 0 -> 1178 bytes public/favicon/icon-48.png | Bin 0 -> 1839 bytes public/favicon/icon-512.png | Bin 0 -> 20500 bytes public/favicon/icon-64.png | Bin 0 -> 2450 bytes public/favicon/maskable-512.png | Bin 0 -> 11933 bytes public/favicon/pwa-192.png | Bin 0 -> 7188 bytes public/favicon/pwa-512.png | Bin 0 -> 20500 bytes public/site.webmanifest | 13 + renovate.json | 64 + scripts/backfill-risk-5x5.ts | 61 + scripts/backup-worker.ts | 41 + scripts/bootstrap-admin.ts | 83 + scripts/build-and-push-images.sh | 58 + scripts/build-c1-scope.ts | 63 + scripts/build-c5-controls.ts | 67 + scripts/check-module-guards.ts | 145 + scripts/encrypt-mfa-secrets.ts | 35 + scripts/garage-provision.ts | 265 + scripts/import-c6-hints.ts | 15 + scripts/import-risk-catalog.ts | 15 + scripts/incident-inbound-worker.ts | 205 + scripts/mail-worker.ts | 56 + .../snapshots/framework-assessment-tisax.json | 1233 ++ scripts/sync-policy-templates.ts | 58 + scripts/sync-role-permissions.ts | 79 + scripts/test-action-error.ts | 99 + scripts/test-action-guard-authz.ts | 132 + scripts/test-assessment-iso.ts | 60 + scripts/test-auth-selfservice.ts | 170 + scripts/test-backup-download.ts | 29 + scripts/test-backup-dsgvo.ts | 118 + scripts/test-backup-isolation.ts | 165 + scripts/test-backup-portal.ts | 157 + scripts/test-backup-target.ts | 168 + scripts/test-doc-control.ts | 73 + scripts/test-framework-assessment.ts | 103 + scripts/test-framework-core.ts | 93 + scripts/test-framework-dryrun.ts | 118 + scripts/test-framework-provision.ts | 106 + scripts/test-framework-templates.ts | 62 + scripts/test-framework-toggle.ts | 150 + scripts/test-ft-rules.ts | 60 + scripts/test-gap-consolidation.ts | 91 + scripts/test-garage-storage.ts | 99 + scripts/test-identity-account.ts | 93 + scripts/test-identity-login.ts | 83 + scripts/test-identity-schema.ts | 123 + scripts/test-incident-deadlines.ts | 205 + scripts/test-incident-inbound.ts | 179 + scripts/test-incident-links.ts | 212 + scripts/test-incidents.ts | 153 + scripts/test-invitation.ts | 103 + scripts/test-mail.ts | 146 + scripts/test-maturity.ts | 98 + scripts/test-mfa-hardening.ts | 106 + scripts/test-password-pepper.ts | 59 + scripts/test-readiness.ts | 56 + scripts/test-reimport.ts | 88 + scripts/test-reset-flow.ts | 203 + scripts/test-review.ts | 78 + scripts/test-rls-enforcement.ts | 180 + scripts/test-rules.ts | 102 + scripts/test-scope-filter.ts | 72 + scripts/test-soa.ts | 67 + scripts/test-tenant-isolation.ts | 159 + scripts/test-tenant-switch.ts | 71 + scripts/test-tenant-users-authz.ts | 142 + scripts/test-two-step-login.ts | 99 + scripts/test-vda-isa.ts | 44 + .../Nachweisregister_zentral.md | 47 + .../Statement-of-Applicability-ISO.md | 135 + .../Technische-Sicherheits-Baseline.md | 113 + .../isms-vorlagenpaket-v2-en/mapping-iso.json | 2219 +++ seed/isms-vorlagenpaket-v2-en/mapping.json | 5351 ++++++ .../richtlinien/D01_Datenschutz.md | 49 + .../L00_Informationssicherheitsleitlinie.md | 175 + .../richtlinien/P01_Prototypenschutz.md | 60 + .../R01_ISMS-Organisation-und-Rollen.md | 294 + ...02_Asset-und-Klassifizierungsrichtlinie.md | 259 + ...03_Risikomanagement-und-Auditrichtlinie.md | 289 + ...ent-Notfall-und-Kontinuitaetsrichtlinie.md | 383 + .../R05_Personalsicherheit-und-Awareness.md | 221 + ...R06_Mobiles-Arbeiten-und-mobile-Geraete.md | 151 + .../richtlinien/R07_Physische-Sicherheit.md | 173 + .../R08_Identitaets-und-Zugriffsmanagement.md | 314 + ...ryptografie-und-Uebertragungsrichtlinie.md | 156 + .../richtlinien/R10_Betriebssicherheit.md | 598 + ...chere-Systembeschaffung-und-Entwicklung.md | 219 + .../R12_Cloud-KI-und-externe-IT-Dienste.md | 117 + ..._Lieferanten-und-Dienstleistersteuerung.md | 250 + .../R14_Compliance-und-Datenschutz.md | 129 + .../variables.schema.json | 379 + ...01_Incident-Response-und-Meldeverfahren.md | 71 + ...02_IT-Notfall-und-Wiederanlaufverfahren.md | 72 + .../verfahren/VA-03_Berechtigungsverfahren.md | 71 + ...4_Change-und-Patch-Management-Verfahren.md | 71 + .../VA-05_Backup-und-Restore-Verfahren.md | 69 + ...A-06_Schwachstellenmanagement-Verfahren.md | 69 + ..._Kryptokonzept-und-Schluesselverwaltung.md | 69 + ...-08_Asset-und-Klassifizierungsverfahren.md | 69 + .../VA-09_Risikomanagement-Verfahren.md | 69 + ...10_Lieferanten-Onboarding-und-Bewertung.md | 69 + .../VA-11_Cloud-und-KI-Freigabeverfahren.md | 69 + .../VA-12_Awareness-und-Schulungsverfahren.md | 69 + .../VA-13_Logging-und-Monitoring-Verfahren.md | 69 + ...-14_Personalsicherheit-Eignungspruefung.md | 71 + ...Interne-Audits-und-Compliancepruefungen.md | 72 + ...ere-Beschaffung-Entwicklung-und-Abnahme.md | 72 + .../VA-17_Zutritts-und-Besuchermanagement.md | 67 + ...VA-18_Datenschutz-und-Compliance-Pflege.md | 66 + ...-19_Informationssicherheit-in-Projekten.md | 70 + .../VA-20_Prototypen-Zutritt-und-Transport.md | 38 + ...tkonformitaeten-und-Korrekturmassnahmen.md | 78 + ...A-22_Managementbewertung-und-Kennzahlen.md | 77 + .../00_Integrationsleitfaden_Wizard.md | 148 + .../ISA-Mapping-Matrix.md | 379 + .../Nachweisregister_zentral.md | 47 + .../Statement-of-Applicability-ISO.md | 135 + .../Technische-Sicherheits-Baseline.md | 113 + seed/isms-vorlagenpaket-v2/_enrich.py | 168 + seed/isms-vorlagenpaket-v2/_fix.py | 21 + seed/isms-vorlagenpaket-v2/_generate_iso.py | 525 + seed/isms-vorlagenpaket-v2/_generate_v2.py | 553 + seed/isms-vorlagenpaket-v2/_generate_v3.py | 173 + .../_generate_verfahren.py | 295 + seed/isms-vorlagenpaket-v2/_isa_de.py | 656 + .../isms-vorlagenpaket-v2/_iso_crosswalk.json | 1735 ++ seed/isms-vorlagenpaket-v2/_iso_sections.json | 81 + .../_iso_sections_en.json | 81 + seed/isms-vorlagenpaket-v2/_iso_texts_en.json | 485 + seed/isms-vorlagenpaket-v2/_matrix.py | 36 + seed/isms-vorlagenpaket-v2/_render_diff.py | 79 + seed/isms-vorlagenpaket-v2/_verify.py | 62 + seed/isms-vorlagenpaket-v2/_verify_iso.py | 138 + seed/isms-vorlagenpaket-v2/mapping-iso.json | 2219 +++ seed/isms-vorlagenpaket-v2/mapping.json | 5351 ++++++ .../richtlinien/D01_Datenschutz.md | 49 + .../L00_Informationssicherheitsleitlinie.md | 175 + .../richtlinien/P01_Prototypenschutz.md | 60 + .../R01_ISMS-Organisation-und-Rollen.md | 294 + ...02_Asset-und-Klassifizierungsrichtlinie.md | 259 + ...03_Risikomanagement-und-Auditrichtlinie.md | 289 + ...ent-Notfall-und-Kontinuitaetsrichtlinie.md | 383 + .../R05_Personalsicherheit-und-Awareness.md | 221 + ...R06_Mobiles-Arbeiten-und-mobile-Geraete.md | 151 + .../richtlinien/R07_Physische-Sicherheit.md | 173 + .../R08_Identitaets-und-Zugriffsmanagement.md | 314 + ...ryptografie-und-Uebertragungsrichtlinie.md | 156 + .../richtlinien/R10_Betriebssicherheit.md | 598 + ...chere-Systembeschaffung-und-Entwicklung.md | 219 + .../R12_Cloud-KI-und-externe-IT-Dienste.md | 117 + ..._Lieferanten-und-Dienstleistersteuerung.md | 250 + .../R14_Compliance-und-Datenschutz.md | 129 + .../variables.schema.json | 379 + ...01_Incident-Response-und-Meldeverfahren.md | 71 + ...02_IT-Notfall-und-Wiederanlaufverfahren.md | 72 + .../verfahren/VA-03_Berechtigungsverfahren.md | 71 + ...4_Change-und-Patch-Management-Verfahren.md | 71 + .../VA-05_Backup-und-Restore-Verfahren.md | 69 + ...A-06_Schwachstellenmanagement-Verfahren.md | 69 + ..._Kryptokonzept-und-Schluesselverwaltung.md | 69 + ...-08_Asset-und-Klassifizierungsverfahren.md | 69 + .../VA-09_Risikomanagement-Verfahren.md | 69 + ...10_Lieferanten-Onboarding-und-Bewertung.md | 69 + .../VA-11_Cloud-und-KI-Freigabeverfahren.md | 69 + .../VA-12_Awareness-und-Schulungsverfahren.md | 69 + .../VA-13_Logging-und-Monitoring-Verfahren.md | 69 + ...-14_Personalsicherheit-Eignungspruefung.md | 71 + ...Interne-Audits-und-Compliancepruefungen.md | 72 + ...ere-Beschaffung-Entwicklung-und-Abnahme.md | 72 + .../VA-17_Zutritts-und-Besuchermanagement.md | 67 + ...VA-18_Datenschutz-und-Compliance-Pflege.md | 66 + ...-19_Informationssicherheit-in-Projekten.md | 70 + .../VA-20_Prototypen-Zutritt-und-Transport.md | 38 + ...tkonformitaeten-und-Korrekturmassnahmen.md | 78 + ...A-22_Managementbewertung-und-Kennzahlen.md | 77 + seed/scoping/c1-scope.json | 3710 ++++ seed/scoping/c5-controls.json | 564 + src/app/(app)/account/page.tsx | 123 + src/app/(app)/assets/[id]/edit/page.tsx | 11 + src/app/(app)/assets/[id]/page.tsx | 11 + src/app/(app)/assets/layout.tsx | 7 + src/app/(app)/assets/new/page.tsx | 6 + src/app/(app)/assets/page.tsx | 454 + .../[auditId]/controls/page.tsx | 217 + .../audit-readiness/[auditId]/export/page.tsx | 90 + .../audit-readiness/[auditId]/layout.tsx | 63 + .../[auditId]/nachweise/page.tsx | 206 + .../[auditId]/nachweise/reassign-select.tsx | 36 + .../(app)/audit-readiness/[auditId]/page.tsx | 12 + .../[auditId]/readiness/page.tsx | 68 + .../audit-readiness/[auditId]/wizard-tabs.tsx | 44 + .../(app)/audit-readiness/audit-dialog.tsx | 186 + src/app/(app)/audit-readiness/export/route.ts | 57 + src/app/(app)/audit-readiness/layout.tsx | 16 + src/app/(app)/audit-readiness/page.tsx | 181 + .../(app)/audit-readiness/steps/gap/step.tsx | 112 + .../audit-readiness/steps/readiness/step.tsx | 148 + .../(app)/audit-readiness/summary/page.tsx | 109 + src/app/(app)/dashboard/page.tsx | 199 + src/app/(app)/dependencies/layout.tsx | 7 + src/app/(app)/dependencies/page.tsx | 132 + src/app/(app)/files/[...key]/route.ts | 70 + src/app/(app)/incidents/export/route.ts | 97 + src/app/(app)/incidents/layout.tsx | 7 + src/app/(app)/incidents/page.tsx | 284 + src/app/(app)/layout.tsx | 227 + src/app/(app)/measures/layout.tsx | 7 + src/app/(app)/measures/page.tsx | 133 + src/app/(app)/onboarding/layout.tsx | 7 + src/app/(app)/onboarding/page.tsx | 250 + .../(app)/onboarding/steps/assets/step.tsx | 143 + .../(app)/onboarding/steps/context/step.tsx | 92 + .../(app)/onboarding/steps/controls/step.tsx | 201 + .../onboarding/steps/criteria/actions.ts | 115 + .../steps/criteria/criteria-edit-dialog.tsx | 48 + .../steps/criteria/criteria-editor.tsx | 301 + .../(app)/onboarding/steps/criteria/step.tsx | 148 + .../information/information-combobox.tsx | 257 + .../onboarding/steps/information/step.tsx | 117 + .../(app)/onboarding/steps/placeholder.tsx | 18 + .../(app)/onboarding/steps/policies/step.tsx | 139 + .../(app)/onboarding/steps/processes/step.tsx | 287 + .../onboarding/steps/protection/step.tsx | 136 + src/app/(app)/onboarding/steps/risks/step.tsx | 130 + .../(app)/onboarding/steps/roles/popup.tsx | 93 + .../steps/roles/role-edit-dialog.tsx | 179 + src/app/(app)/onboarding/steps/roles/step.tsx | 179 + .../(app)/onboarding/steps/scoping/step.tsx | 107 + src/app/(app)/policies/[code]/edit/page.tsx | 220 + src/app/(app)/policies/[code]/page.tsx | 120 + src/app/(app)/policies/control/page.tsx | 127 + src/app/(app)/policies/hints/page.tsx | 107 + src/app/(app)/policies/layout.tsx | 7 + src/app/(app)/policies/page.tsx | 389 + src/app/(app)/policies/updates/page.tsx | 123 + src/app/(app)/policies/upload/page.tsx | 56 + src/app/(app)/processes/[id]/edit/page.tsx | 11 + src/app/(app)/processes/[id]/page.tsx | 11 + src/app/(app)/processes/layout.tsx | 7 + src/app/(app)/processes/new/page.tsx | 6 + src/app/(app)/processes/page.tsx | 537 + src/app/(app)/review/page.tsx | 234 + src/app/(app)/risks/catalog/page.tsx | 101 + src/app/(app)/risks/layout.tsx | 7 + src/app/(app)/risks/page.tsx | 290 + .../(app)/settings/incident-intake/page.tsx | 117 + src/app/(app)/settings/page.tsx | 226 + src/app/(app)/settings/risk-criteria/page.tsx | 72 + src/app/(app)/settings/users/page.tsx | 110 + src/app/(app)/soa/export/route.ts | 117 + src/app/(app)/soa/page.tsx | 155 + src/app/(app)/suppliers/layout.tsx | 7 + src/app/(app)/suppliers/page.tsx | 327 + src/app/(app)/tasks/layout.tsx | 7 + src/app/(app)/tasks/page.tsx | 350 + src/app/(platform)/admin/[id]/page.tsx | 575 + src/app/(platform)/admin/backup/page.tsx | 70 + src/app/(platform)/admin/page.tsx | 238 + src/app/(platform)/admins/page.tsx | 94 + src/app/(platform)/layout.tsx | 51 + src/app/(platform)/profile/page.tsx | 106 + .../templates/[locale]/[code]/page.tsx | 73 + .../templates/[locale]/requirements/page.tsx | 106 + .../templates/[locale]/variables/page.tsx | 114 + src/app/(platform)/templates/page.tsx | 195 + src/app/api/auth/[...nextauth]/route.ts | 3 + .../api/platform-auth/[...nextauth]/route.ts | 3 + src/app/api/platform/backup/download/route.ts | 62 + src/app/api/platform/dsgvo/[token]/route.ts | 82 + src/app/change-password/page.tsx | 43 + src/app/enroll-mfa/page.tsx | 75 + src/app/error.tsx | 38 + src/app/fonts/open-sans-300.woff2 | Bin 0 -> 18660 bytes src/app/fonts/open-sans-400.woff2 | Bin 0 -> 18640 bytes src/app/fonts/open-sans-600.woff2 | Bin 0 -> 18620 bytes src/app/fonts/open-sans-700.woff2 | Bin 0 -> 18204 bytes src/app/fonts/poppins-300.woff2 | Bin 0 -> 7840 bytes src/app/fonts/poppins-500.woff2 | Bin 0 -> 7748 bytes src/app/fonts/poppins-600.woff2 | Bin 0 -> 8000 bytes src/app/fonts/poppins-700.woff2 | Bin 0 -> 7816 bytes src/app/forgot-password/page.tsx | 48 + src/app/globals.css | 442 + src/app/invite/page.tsx | 65 + src/app/layout.tsx | 88 + src/app/login/mfa/page.tsx | 89 + src/app/login/page.tsx | 130 + src/app/not-found.tsx | 28 + src/app/page.tsx | 5 + src/app/platform/enroll-mfa/page.tsx | 55 + src/app/platform/login/page.tsx | 92 + src/app/reset/page.tsx | 82 + src/app/select-tenant/page.tsx | 56 + src/app/verify-email/page.tsx | 60 + src/components/asset-form.tsx | 129 + src/components/asset-modals.tsx | 333 + src/components/audit-trail.tsx | 140 + src/components/auth-recovery-forms.tsx | 197 + src/components/backup-admin-panel.tsx | 214 + src/components/backup-target-form.tsx | 121 + src/components/bia-popup.tsx | 735 + src/components/brand/certvia-logo.tsx | 119 + src/components/brand/powered-by-gefim.tsx | 37 + src/components/brand/tenant-brand.tsx | 35 + src/components/dependency-graph.tsx | 344 + src/components/filter-tabs.tsx | 28 + src/components/force-password-change-form.tsx | 30 + src/components/generic-register.tsx | 88 + src/components/incident-deadlines.tsx | 114 + src/components/incident-modals.tsx | 765 + src/components/kanban-board.tsx | 218 + src/components/mail-status-panel.tsx | 126 + src/components/measure-modals.tsx | 275 + src/components/mockup-ui.tsx | 199 + src/components/modal.tsx | 48 + src/components/nav-link.tsx | 34 + src/components/object-review.tsx | 114 + src/components/passkey-login-button.tsx | 46 + src/components/passkey-manager.tsx | 62 + src/components/platform-admin-forms.tsx | 72 + src/components/platform-enroll-form.tsx | 58 + src/components/policy-domain-view.tsx | 235 + src/components/policy-expert-editor.tsx | 126 + src/components/policy-modals.tsx | 116 + src/components/policy-registers.tsx | 411 + src/components/process-form.tsx | 142 + src/components/process-modals.tsx | 927 + src/components/project-modals.tsx | 277 + src/components/risk-modals.tsx | 849 + src/components/role-manager.tsx | 148 + src/components/segmented-rating.tsx | 67 + src/components/service-modals.tsx | 373 + src/components/software-modals.tsx | 280 + src/components/supplier-cockpit.tsx | 217 + src/components/supplier-modals.tsx | 447 + src/components/task-modals.tsx | 364 + src/components/tenant-mfa-enroll-form.tsx | 42 + src/components/tenant-recovery-regen-form.tsx | 37 + src/components/tenant-switcher.tsx | 40 + src/components/ui-locale-switcher.tsx | 44 + src/components/ui/badge.tsx | 52 + src/components/ui/button.tsx | 59 + src/components/ui/card.tsx | 103 + src/components/ui/input.tsx | 20 + src/components/ui/label.tsx | 20 + src/components/ui/select.tsx | 201 + src/components/ui/separator.tsx | 25 + src/components/ui/table.tsx | 116 + src/components/ui/tabs.tsx | 82 + src/components/ui/textarea.tsx | 18 + src/components/user-forms.tsx | 135 + src/components/user-table.tsx | 63 + src/i18n/request.ts | 37 + src/lib/assessment.ts | 102 + src/lib/asset-labels.ts | 34 + src/lib/audit-readiness/activation.ts | 23 + src/lib/brand.ts | 117 + src/lib/control-domain.ts | 128 + src/lib/control-specs-iso.ts | 147 + src/lib/control-titles-iso.ts | 133 + src/lib/control-titles.ts | 79 + src/lib/document-brand.ts | 73 + src/lib/email-brand.ts | 133 + src/lib/export/vda-isa.ts | 145 + src/lib/ft-rules.ts | 114 + src/lib/gap-consolidation.ts | 165 + src/lib/incident-deadlines.ts | 278 + src/lib/incident-export.ts | 270 + src/lib/incident-report-html.ts | 232 + src/lib/incident-severity.ts | 60 + src/lib/incident.ts | 116 + src/lib/isa-controls.ts | 22 + src/lib/isb-bestellung.ts | 46 + src/lib/iso-isa-crosswalk.ts | 108 + src/lib/levels.ts | 13 + src/lib/maturity.ts | 217 + src/lib/measure.ts | 15 + src/lib/mfa-policy.ts | 10 + src/lib/modules.ts | 36 + src/lib/normalize-asset.ts | 86 + src/lib/object-review.ts | 45 + src/lib/onboarding/facts.ts | 63 + src/lib/onboarding/functions.ts | 115 + src/lib/onboarding/questions.ts | 91 + src/lib/onboarding/register-steps.ts | 62 + src/lib/onboarding/registry.ts | 91 + src/lib/onboarding/state.ts | 70 + src/lib/password-policy.ts | 54 + src/lib/policy-render.ts | 260 + src/lib/policy-titles.ts | 64 + src/lib/policy-variables.ts | 15 + src/lib/readiness.ts | 118 + src/lib/review-cycle.ts | 37 + src/lib/risk.ts | 37 + src/lib/rules/dsl.ts | 69 + src/lib/rules/engine.ts | 62 + src/lib/rules/feature-rules.ts | 141 + src/lib/scope-filter.ts | 78 + src/lib/soa.ts | 78 + src/lib/supplier-include.ts | 45 + src/lib/supplier.ts | 193 + src/lib/task-triggers.ts | 131 + src/lib/tasks.ts | 95 + src/lib/utils.ts | 6 + src/proxy.ts | 65 + src/server/action-error.ts | 122 + src/server/action-guard.ts | 90 + src/server/actions/account.ts | 160 + src/server/actions/admin.ts | 272 + src/server/actions/assets.ts | 163 + src/server/actions/audit-evidence.ts | 314 + src/server/actions/audits.ts | 157 + src/server/actions/auth-recovery.ts | 457 + src/server/actions/backup-admin.ts | 300 + src/server/actions/backup-settings.ts | 278 + src/server/actions/control-descriptions.ts | 124 + src/server/actions/gap.ts | 73 + src/server/actions/hints.ts | 34 + src/server/actions/incident-intake-admin.ts | 105 + src/server/actions/incident-intake.ts | 70 + src/server/actions/incidents.ts | 872 + src/server/actions/mail.ts | 116 + src/server/actions/measures.ts | 253 + src/server/actions/onboarding-facts.ts | 62 + src/server/actions/onboarding-steps.ts | 63 + src/server/actions/onboarding-team.ts | 210 + src/server/actions/onboarding.ts | 211 + src/server/actions/platform-admins.ts | 104 + src/server/actions/platform-users.ts | 169 + src/server/actions/platform.ts | 88 + src/server/actions/policies.ts | 320 + src/server/actions/policy-control.ts | 75 + src/server/actions/policy-package.ts | 54 + src/server/actions/policy-templates.ts | 313 + src/server/actions/policy-upload.ts | 186 + src/server/actions/processes.ts | 553 + src/server/actions/projects.ts | 92 + src/server/actions/register.ts | 69 + src/server/actions/review.ts | 234 + src/server/actions/risk-catalog.ts | 242 + src/server/actions/risks.ts | 368 + src/server/actions/services.ts | 126 + src/server/actions/soa-entries.ts | 52 + src/server/actions/soa.ts | 185 + src/server/actions/software.ts | 96 + src/server/actions/structure.ts | 446 + src/server/actions/suppliers.ts | 299 + src/server/actions/tasks.ts | 643 + src/server/actions/tenant-settings.ts | 57 + src/server/actions/tenant-switch.ts | 47 + src/server/actions/tenant-users.ts | 313 + src/server/actions/webauthn.ts | 96 + src/server/ai/client.ts | 41 + src/server/ai/draft-control-description.ts | 127 + src/server/assessment-level.ts | 30 + src/server/assessment.ts | 136 + src/server/audit.ts | 56 + src/server/auth-selfservice.ts | 321 + src/server/auth-token.ts | 157 + src/server/auth.ts | 442 + src/server/backup/crypto.ts | 56 + src/server/backup/dsgvo-zip.ts | 100 + src/server/backup/export.ts | 208 + src/server/backup/index.ts | 26 + src/server/backup/job.ts | 44 + src/server/backup/ops.ts | 128 + src/server/backup/queue.ts | 130 + src/server/backup/restore-confirm.ts | 15 + src/server/backup/restore.ts | 301 + src/server/backup/serialization.ts | 105 + src/server/backup/topology.ts | 450 + src/server/backup/worker.ts | 49 + src/server/backup/zip.ts | 115 + src/server/control-descriptions-context.ts | 145 + src/server/control-domain.ts | 201 + src/server/db.ts | 430 + src/server/dependency-graph.ts | 284 + src/server/dsgvo/deletion.ts | 245 + src/server/dsgvo/export.ts | 112 + src/server/dsgvo/pii-fields.ts | 42 + src/server/dsgvo/tombstone.ts | 58 + src/server/env.ts | 59 + src/server/export-context.ts | 69 + src/server/export/incident-xlsx.ts | 37 + src/server/export/soa-xlsx.ts | 30 + src/server/export/vda-isa-xlsx.ts | 57 + src/server/gap-context.ts | 122 + src/server/incident-export-context.ts | 206 + src/server/incident-inbound/parse.ts | 210 + src/server/incident-inbound/process.ts | 135 + src/server/incident-inbound/route.ts | 144 + src/server/incident-refno.ts | 35 + src/server/iso-hints.ts | 80 + src/server/login-ticket.ts | 62 + src/server/mail/config.ts | 102 + src/server/mail/deliver.ts | 91 + src/server/mail/incident-notifications.ts | 294 + src/server/mail/job.ts | 34 + src/server/mail/notifications.ts | 221 + src/server/mail/provider-smtp.ts | 110 + src/server/mail/provider.ts | 37 + src/server/mail/queue.ts | 174 + src/server/mail/service.ts | 115 + src/server/mail/templates.ts | 276 + src/server/mail/worker.ts | 120 + src/server/mfa.ts | 122 + src/server/modules.ts | 53 + src/server/object-review.ts | 100 + src/server/password.ts | 105 + src/server/platform-auth.ts | 272 + src/server/platform-settings.ts | 10 + src/server/policies/derive-domains.ts | 40 + src/server/provision.ts | 189 + src/server/rate-limit.ts | 101 + src/server/rbac.ts | 181 + src/server/risk-calc.ts | 43 + src/server/roles.ts | 98 + src/server/secret-crypto.ts | 41 + src/server/sessions.ts | 106 + src/server/soa-context.ts | 174 + src/server/soa-statement.ts | 114 + src/server/storage/adapter.ts | 209 + src/server/storage/backup-store.ts | 336 + src/server/task-sync.ts | 186 + src/server/task-visibility.ts | 56 + src/server/webauthn.ts | 108 + src/types/next-auth.d.ts | 70 + tsconfig.json | 34 + types/mailparser.d.ts | 5 + 720 files changed, 140143 insertions(+) create mode 100644 .claude/launch.json create mode 100644 .dockerignore create mode 100644 .env.coolify.example create mode 100644 .env.example create mode 100644 .env.prod.example create mode 100644 .gitea/workflows/ci.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 components.json create mode 100644 deploy/garage.toml create mode 100644 docker-compose.coolify.prebuilt.yml create mode 100644 docker-compose.coolify.yml create mode 100644 docker-compose.yml create mode 100644 docs/BRANDING-CERTVIA.md create mode 100644 docs/DEPLOY-COOLIFY.md create mode 100644 docs/DEPLOY-PROD-CONTABO.md create mode 100644 docs/DEPLOY-PROD-PREBUILT.md create mode 100644 docs/DEVOPS-INTEGRATION-RUNBOOK.md create mode 100644 docs/FEINDESIGN-framework-assessment.md create mode 100644 docs/FEINDESIGN-identity-mandanten.md create mode 100644 docs/FRAMEWORK-MAPPING-ISO27001.md create mode 100644 docs/HANDBUCH-KUNDENBETREUUNG.md create mode 100644 docs/HANDOVER-DEV.md create mode 100644 docs/HANDOVER-DEVOPS.md create mode 100644 docs/HANDOVER-PM.md create mode 100644 docs/IMPL-tisax-wizard-neustruktur.md create mode 100644 docs/ISMS-Abhaengigkeitskarte-GEFIM.html create mode 100644 docs/ISMS-GUI-Verbesserungen-GEFIM.html create mode 100644 docs/ISMS-Lieferantenmanagement-GEFIM.html create mode 100644 docs/ISMS-Prototyp-GEFIM.html create mode 100644 docs/KONZEPT-backup-restore.md create mode 100644 docs/KONZEPT-backup-target.md create mode 100644 docs/KONZEPT-framework-iso27001.md create mode 100644 docs/KONZEPT-garage-migration.md create mode 100644 docs/KONZEPT-haertung.md create mode 100644 docs/KONZEPT-identity-mandanten.md create mode 100644 docs/KONZEPT-incidents.md create mode 100644 docs/KONZEPT-ui-i18n.md create mode 100644 docs/MOCKUP-bia-prozessuebersicht.html create mode 100644 docs/ONBOARDING-AGENT.md create mode 100644 docs/PROMPT-lane-backup-target.md create mode 100644 docs/PROMPT-lane-backup.md create mode 100644 docs/PROMPT-lane-framework-assessment.md create mode 100644 docs/PROMPT-lane-framework-iso27001.md create mode 100644 docs/PROMPT-lane-garage-abnahme.md create mode 100644 docs/PROMPT-lane-garage-code.md create mode 100644 docs/PROMPT-lane-garage-infra.md create mode 100644 docs/PROMPT-lane-garage-provision.md create mode 100644 docs/PROMPT-lane-haertung.md create mode 100644 docs/PROMPT-lane-ui-i18n.md create mode 100644 docs/PROMPT-uebergabe-identity-mandanten.md create mode 100644 docs/PROMPT-uebergabe-kundenbetreuung.md create mode 100644 docs/SEC1-MAIL.md create mode 100644 docs/SEC2-AUTH-SELFSERVICE.md create mode 100644 docs/SECRETS-REGISTER.md create mode 100644 docs/SPEC.md create mode 100644 docs/STAND-dev-branch.md create mode 100644 docs/UEBERGABE-framework-iso27001.md create mode 100644 docs/UEBERGABE-identity-mandanten.md create mode 100644 docs/branding/Aufgabenpaket-Branding-Certvia.md create mode 100644 docs/branding/README-Logo.md create mode 100644 docs/craftvia/BRANDBOOK.md create mode 100644 docs/craftvia/SPEC-CRAFTVIA.md create mode 100644 docs/craftvia/assets/craftvia-brand-identity-v1.png create mode 100644 docs/reviews/richtlinien-gap-report.md create mode 100644 docs/sicherheit/Aufgabenpaket-Sicherheit-Administration.md create mode 100644 docs/sicherheit/README.md create mode 100644 docs/sicherheit/SEC1-Mail-Fundament-Detail.md create mode 100644 docs/sicherheit/SEC2-Auth-SelfService-Detail.md create mode 100644 docs/sicherheit/Sicherheit-und-Administration-Konzept.md create mode 100644 docs/wizard-uebergabe/00_Entwicklerpakete/Contracts-Checkliste-Kickoff.md create mode 100644 docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevA-Wizard-Scoping.md create mode 100644 docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevB-Engines-Richtlinien.md create mode 100644 docs/wizard-uebergabe/01_Planung/Berater-Anweisung-Fachcontent.md create mode 100644 docs/wizard-uebergabe/01_Planung/Onboarding-Wizard-Machbarkeitsanalyse.md create mode 100644 docs/wizard-uebergabe/01_Planung/Wizard-Entwickler-Backlog.md create mode 100644 docs/wizard-uebergabe/01_Planung/Wizard-Stories.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C0_README-Fachcontent-Uebersicht.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C1_Scoping-AL-Pruefziel.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C2_Fragenkatalog-Wirkung.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C3_Vorlagen-Annotation.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C4_Risikokatalog.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C5_Reifegradlogik.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C6_Umsetzungshinweise.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C7_Rollen-Funktionstrennung.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C8_Priorisierung-Gap.md create mode 100644 docs/wizard-uebergabe/02_Fachcontent_C1-C9/C9_Auswertung-Export.md create mode 100644 docs/wizard-uebergabe/03_Referenz/Onboarding_Wizard_Fahrplan_Detail.md create mode 100644 docs/wizard-uebergabe/03_Referenz/STAND-dev-branch.HINWEIS.md create mode 100644 docs/wizard-uebergabe/README.md create mode 100644 eslint.config.mjs create mode 100644 messages/de.json create mode 100644 messages/en.json create mode 100644 next.config.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 prisma.config.ts create mode 100644 prisma/import-hints.ts create mode 100644 prisma/import-managed.ts create mode 100644 prisma/import-policies.ts create mode 100644 prisma/import-process-catalog.ts create mode 100644 prisma/import-risks.ts create mode 100644 prisma/migrations/20260702095800_init/migration.sql create mode 100644 prisma/migrations/20260702095816_row_level_security/migration.sql create mode 100644 prisma/migrations/20260702101647_assets_bia/migration.sql create mode 100644 prisma/migrations/20260702101701_rls_assets_bia/migration.sql create mode 100644 prisma/migrations/20260702132947_risks_and_process_category/migration.sql create mode 100644 prisma/migrations/20260702133003_rls_risks/migration.sql create mode 100644 prisma/migrations/20260702135246_measures/migration.sql create mode 100644 prisma/migrations/20260702135301_rls_measures/migration.sql create mode 100644 prisma/migrations/20260702144829_decimal_reductions_and_catalogs/migration.sql create mode 100644 prisma/migrations/20260703081059_suppliers/migration.sql create mode 100644 prisma/migrations/20260703081120_rls_suppliers/migration.sql create mode 100644 prisma/migrations/20260703113715_suppliers_as_assets/migration.sql create mode 100644 prisma/migrations/20260707132008_policies/migration.sql create mode 100644 prisma/migrations/20260707153909_managed_tables/migration.sql create mode 100644 prisma/migrations/20260707163523_policy_approval/migration.sql create mode 100644 prisma/migrations/20260708111123_policy_protection_override/migration.sql create mode 100644 prisma/migrations/20260719203024_admin_console/migration.sql create mode 100644 prisma/migrations/20260720183635_platform_admins/migration.sql create mode 100644 prisma/migrations/20260721113710_policy_lifecycle_archived/migration.sql create mode 100644 prisma/migrations/20260722071432_user_mgmt_and_platform_settings/migration.sql create mode 100644 prisma/migrations/20260722092625_tasks/migration.sql create mode 100644 prisma/migrations/20260723071617_strip_tool_variable_articles/migration.sql create mode 100644 prisma/migrations/20260723090004_managed_registers/migration.sql create mode 100644 prisma/migrations/20260724095408_software_and_project_assets/migration.sql create mode 100644 prisma/migrations/20260728104412_tasks_wizard_fields/migration.sql create mode 100644 prisma/migrations/20260728105241_onboarding_progress/migration.sql create mode 100644 prisma/migrations/20260728115109_object_review_status/migration.sql create mode 100644 prisma/migrations/20260728122213_wizard_facts/migration.sql create mode 100644 prisma/migrations/20260728153225_wizard_scope/migration.sql create mode 100644 prisma/migrations/20260728154046_implementation_hints/migration.sql create mode 100644 prisma/migrations/20260728161306_policy_package_state/migration.sql create mode 100644 prisma/migrations/20260729101027_risk_catalog/migration.sql create mode 100644 prisma/migrations/20260729103725_risk_acceptance/migration.sql create mode 100644 prisma/migrations/20260729120000_control_assessments/migration.sql create mode 100644 prisma/migrations/20260729140000_task_description/migration.sql create mode 100644 prisma/migrations/20260729150000_control_implementations/migration.sql create mode 100644 prisma/migrations/20260730111105_login_lockout/migration.sql create mode 100644 prisma/migrations/20260730160000_rls_enforce/migration.sql create mode 100644 prisma/migrations/20260730170000_mfa_totp_replay/migration.sql create mode 100644 prisma/migrations/20260730180000_mail_fundament/migration.sql create mode 100644 prisma/migrations/20260730190000_auth_tokens_sessions/migration.sql create mode 100644 prisma/migrations/20260731120000_webauthn_credentials/migration.sql create mode 100644 prisma/migrations/20260731123409_tisax_m0_foundation/migration.sql create mode 100644 prisma/migrations/20260731130000_platform_admin_role/migration.sql create mode 100644 prisma/migrations/20260731152213_tisax_m1_m4_consolidated/migration.sql create mode 100644 prisma/migrations/20260731154215_tisax_rekey_onboarding_steps/migration.sql create mode 100644 prisma/migrations/20260731165818_tisax_v3_process_fields/migration.sql create mode 100644 prisma/migrations/20260801134128_tisax_v4_catalog_parent/migration.sql create mode 100644 prisma/migrations/20260804111342_tisax_v5_audit/migration.sql create mode 100644 prisma/migrations/20260805093503_tisax_v7_policy_domain/migration.sql create mode 100644 prisma/migrations/20260810120000_policy_templates/migration.sql create mode 100644 prisma/migrations/20260811120000_identity_foundation/migration.sql create mode 100644 prisma/migrations/20260811140000_webauthn_identity/migration.sql create mode 100644 prisma/migrations/20260811150000_contract_user_auth_columns/migration.sql create mode 100644 prisma/migrations/20260811160000_identity_ui_locale/migration.sql create mode 100644 prisma/migrations/20260812090000_backup_dsgvo_foundation/migration.sql create mode 100644 prisma/migrations/20260812100000_backup_jobs/migration.sql create mode 100644 prisma/migrations/20260817120000_backup_target_config/migration.sql create mode 100644 prisma/migrations/20260817130000_incidents/migration.sql create mode 100644 prisma/migrations/20260818090000_incident_links_c/migration.sql create mode 100644 prisma/migrations/20260818100000_incident_inbound_d/migration.sql create mode 100644 prisma/migrations/20260821090000_framework_core/migration.sql create mode 100644 prisma/migrations/20260821100000_soa_entries/migration.sql create mode 100644 prisma/migrations/20260821110000_mgmt_clauses/migration.sql create mode 100644 prisma/migrations/20260821120000_doc_control/migration.sql create mode 100644 prisma/migrations/20260907084110_add_process_dependencies/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 prisma/seed-content.ts create mode 100644 prisma/seed.ts create mode 100644 prisma/template-store.ts create mode 100644 public/assets/logo/certvia-favicon.svg create mode 100644 public/assets/logo/certvia-lockup-positiv-1024.png create mode 100644 public/assets/logo/certvia-lockup-positiv.svg create mode 100644 public/assets/logo/certvia-mark-anthrazit.svg create mode 100644 public/assets/logo/certvia-mark-grau.svg create mode 100644 public/assets/logo/certvia-mark-negativ-512.png create mode 100644 public/assets/logo/certvia-mark-negativ.svg create mode 100644 public/assets/logo/certvia-mark-positiv-512.png create mode 100644 public/assets/logo/certvia-mark-positiv.svg create mode 100644 public/assets/logo/gefim-logo.png create mode 100644 public/favicon.ico create mode 100644 public/favicon/apple-touch-icon-180.png create mode 100644 public/favicon/icon-16.png create mode 100644 public/favicon/icon-32.png create mode 100644 public/favicon/icon-48.png create mode 100644 public/favicon/icon-512.png create mode 100644 public/favicon/icon-64.png create mode 100644 public/favicon/maskable-512.png create mode 100644 public/favicon/pwa-192.png create mode 100644 public/favicon/pwa-512.png create mode 100644 public/site.webmanifest create mode 100644 renovate.json create mode 100644 scripts/backfill-risk-5x5.ts create mode 100644 scripts/backup-worker.ts create mode 100644 scripts/bootstrap-admin.ts create mode 100755 scripts/build-and-push-images.sh create mode 100644 scripts/build-c1-scope.ts create mode 100644 scripts/build-c5-controls.ts create mode 100644 scripts/check-module-guards.ts create mode 100644 scripts/encrypt-mfa-secrets.ts create mode 100644 scripts/garage-provision.ts create mode 100644 scripts/import-c6-hints.ts create mode 100644 scripts/import-risk-catalog.ts create mode 100644 scripts/incident-inbound-worker.ts create mode 100644 scripts/mail-worker.ts create mode 100644 scripts/snapshots/framework-assessment-tisax.json create mode 100644 scripts/sync-policy-templates.ts create mode 100644 scripts/sync-role-permissions.ts create mode 100644 scripts/test-action-error.ts create mode 100644 scripts/test-action-guard-authz.ts create mode 100644 scripts/test-assessment-iso.ts create mode 100644 scripts/test-auth-selfservice.ts create mode 100644 scripts/test-backup-download.ts create mode 100644 scripts/test-backup-dsgvo.ts create mode 100644 scripts/test-backup-isolation.ts create mode 100644 scripts/test-backup-portal.ts create mode 100644 scripts/test-backup-target.ts create mode 100644 scripts/test-doc-control.ts create mode 100644 scripts/test-framework-assessment.ts create mode 100644 scripts/test-framework-core.ts create mode 100644 scripts/test-framework-dryrun.ts create mode 100644 scripts/test-framework-provision.ts create mode 100644 scripts/test-framework-templates.ts create mode 100644 scripts/test-framework-toggle.ts create mode 100644 scripts/test-ft-rules.ts create mode 100644 scripts/test-gap-consolidation.ts create mode 100644 scripts/test-garage-storage.ts create mode 100644 scripts/test-identity-account.ts create mode 100644 scripts/test-identity-login.ts create mode 100644 scripts/test-identity-schema.ts create mode 100644 scripts/test-incident-deadlines.ts create mode 100644 scripts/test-incident-inbound.ts create mode 100644 scripts/test-incident-links.ts create mode 100644 scripts/test-incidents.ts create mode 100644 scripts/test-invitation.ts create mode 100644 scripts/test-mail.ts create mode 100644 scripts/test-maturity.ts create mode 100644 scripts/test-mfa-hardening.ts create mode 100644 scripts/test-password-pepper.ts create mode 100644 scripts/test-readiness.ts create mode 100644 scripts/test-reimport.ts create mode 100644 scripts/test-reset-flow.ts create mode 100644 scripts/test-review.ts create mode 100644 scripts/test-rls-enforcement.ts create mode 100644 scripts/test-rules.ts create mode 100644 scripts/test-scope-filter.ts create mode 100644 scripts/test-soa.ts create mode 100644 scripts/test-tenant-isolation.ts create mode 100644 scripts/test-tenant-switch.ts create mode 100644 scripts/test-tenant-users-authz.ts create mode 100644 scripts/test-two-step-login.ts create mode 100644 scripts/test-vda-isa.ts create mode 100644 seed/isms-vorlagenpaket-v2-en/Nachweisregister_zentral.md create mode 100644 seed/isms-vorlagenpaket-v2-en/Statement-of-Applicability-ISO.md create mode 100644 seed/isms-vorlagenpaket-v2-en/Technische-Sicherheits-Baseline.md create mode 100644 seed/isms-vorlagenpaket-v2-en/mapping-iso.json create mode 100644 seed/isms-vorlagenpaket-v2-en/mapping.json create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/D01_Datenschutz.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/L00_Informationssicherheitsleitlinie.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/P01_Prototypenschutz.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R01_ISMS-Organisation-und-Rollen.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R05_Personalsicherheit-und-Awareness.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R07_Physische-Sicherheit.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R10_Betriebssicherheit.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md create mode 100644 seed/isms-vorlagenpaket-v2-en/richtlinien/R14_Compliance-und-Datenschutz.md create mode 100644 seed/isms-vorlagenpaket-v2-en/variables.schema.json create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-03_Berechtigungsverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-05_Backup-und-Restore-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-09_Risikomanagement-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-12_Awareness-und-Schulungsverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-17_Zutritts-und-Besuchermanagement.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-19_Informationssicherheit-in-Projekten.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md create mode 100644 seed/isms-vorlagenpaket-v2-en/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md create mode 100644 seed/isms-vorlagenpaket-v2/00_Integrationsleitfaden_Wizard.md create mode 100644 seed/isms-vorlagenpaket-v2/ISA-Mapping-Matrix.md create mode 100644 seed/isms-vorlagenpaket-v2/Nachweisregister_zentral.md create mode 100644 seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md create mode 100644 seed/isms-vorlagenpaket-v2/Technische-Sicherheits-Baseline.md create mode 100644 seed/isms-vorlagenpaket-v2/_enrich.py create mode 100644 seed/isms-vorlagenpaket-v2/_fix.py create mode 100644 seed/isms-vorlagenpaket-v2/_generate_iso.py create mode 100644 seed/isms-vorlagenpaket-v2/_generate_v2.py create mode 100644 seed/isms-vorlagenpaket-v2/_generate_v3.py create mode 100644 seed/isms-vorlagenpaket-v2/_generate_verfahren.py create mode 100644 seed/isms-vorlagenpaket-v2/_isa_de.py create mode 100644 seed/isms-vorlagenpaket-v2/_iso_crosswalk.json create mode 100644 seed/isms-vorlagenpaket-v2/_iso_sections.json create mode 100644 seed/isms-vorlagenpaket-v2/_iso_sections_en.json create mode 100644 seed/isms-vorlagenpaket-v2/_iso_texts_en.json create mode 100644 seed/isms-vorlagenpaket-v2/_matrix.py create mode 100644 seed/isms-vorlagenpaket-v2/_render_diff.py create mode 100644 seed/isms-vorlagenpaket-v2/_verify.py create mode 100644 seed/isms-vorlagenpaket-v2/_verify_iso.py create mode 100644 seed/isms-vorlagenpaket-v2/mapping-iso.json create mode 100644 seed/isms-vorlagenpaket-v2/mapping.json create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/D01_Datenschutz.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/L00_Informationssicherheitsleitlinie.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/P01_Prototypenschutz.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R01_ISMS-Organisation-und-Rollen.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R05_Personalsicherheit-und-Awareness.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R07_Physische-Sicherheit.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R10_Betriebssicherheit.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md create mode 100644 seed/isms-vorlagenpaket-v2/richtlinien/R14_Compliance-und-Datenschutz.md create mode 100644 seed/isms-vorlagenpaket-v2/variables.schema.json create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-03_Berechtigungsverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-05_Backup-und-Restore-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-09_Risikomanagement-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-12_Awareness-und-Schulungsverfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-17_Zutritts-und-Besuchermanagement.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-19_Informationssicherheit-in-Projekten.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md create mode 100644 seed/isms-vorlagenpaket-v2/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md create mode 100644 seed/scoping/c1-scope.json create mode 100644 seed/scoping/c5-controls.json create mode 100644 src/app/(app)/account/page.tsx create mode 100644 src/app/(app)/assets/[id]/edit/page.tsx create mode 100644 src/app/(app)/assets/[id]/page.tsx create mode 100644 src/app/(app)/assets/layout.tsx create mode 100644 src/app/(app)/assets/new/page.tsx create mode 100644 src/app/(app)/assets/page.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/controls/page.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/export/page.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/layout.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/nachweise/page.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/nachweise/reassign-select.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/page.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/readiness/page.tsx create mode 100644 src/app/(app)/audit-readiness/[auditId]/wizard-tabs.tsx create mode 100644 src/app/(app)/audit-readiness/audit-dialog.tsx create mode 100644 src/app/(app)/audit-readiness/export/route.ts create mode 100644 src/app/(app)/audit-readiness/layout.tsx create mode 100644 src/app/(app)/audit-readiness/page.tsx create mode 100644 src/app/(app)/audit-readiness/steps/gap/step.tsx create mode 100644 src/app/(app)/audit-readiness/steps/readiness/step.tsx create mode 100644 src/app/(app)/audit-readiness/summary/page.tsx create mode 100644 src/app/(app)/dashboard/page.tsx create mode 100644 src/app/(app)/dependencies/layout.tsx create mode 100644 src/app/(app)/dependencies/page.tsx create mode 100644 src/app/(app)/files/[...key]/route.ts create mode 100644 src/app/(app)/incidents/export/route.ts create mode 100644 src/app/(app)/incidents/layout.tsx create mode 100644 src/app/(app)/incidents/page.tsx create mode 100644 src/app/(app)/layout.tsx create mode 100644 src/app/(app)/measures/layout.tsx create mode 100644 src/app/(app)/measures/page.tsx create mode 100644 src/app/(app)/onboarding/layout.tsx create mode 100644 src/app/(app)/onboarding/page.tsx create mode 100644 src/app/(app)/onboarding/steps/assets/step.tsx create mode 100644 src/app/(app)/onboarding/steps/context/step.tsx create mode 100644 src/app/(app)/onboarding/steps/controls/step.tsx create mode 100644 src/app/(app)/onboarding/steps/criteria/actions.ts create mode 100644 src/app/(app)/onboarding/steps/criteria/criteria-edit-dialog.tsx create mode 100644 src/app/(app)/onboarding/steps/criteria/criteria-editor.tsx create mode 100644 src/app/(app)/onboarding/steps/criteria/step.tsx create mode 100644 src/app/(app)/onboarding/steps/information/information-combobox.tsx create mode 100644 src/app/(app)/onboarding/steps/information/step.tsx create mode 100644 src/app/(app)/onboarding/steps/placeholder.tsx create mode 100644 src/app/(app)/onboarding/steps/policies/step.tsx create mode 100644 src/app/(app)/onboarding/steps/processes/step.tsx create mode 100644 src/app/(app)/onboarding/steps/protection/step.tsx create mode 100644 src/app/(app)/onboarding/steps/risks/step.tsx create mode 100644 src/app/(app)/onboarding/steps/roles/popup.tsx create mode 100644 src/app/(app)/onboarding/steps/roles/role-edit-dialog.tsx create mode 100644 src/app/(app)/onboarding/steps/roles/step.tsx create mode 100644 src/app/(app)/onboarding/steps/scoping/step.tsx create mode 100644 src/app/(app)/policies/[code]/edit/page.tsx create mode 100644 src/app/(app)/policies/[code]/page.tsx create mode 100644 src/app/(app)/policies/control/page.tsx create mode 100644 src/app/(app)/policies/hints/page.tsx create mode 100644 src/app/(app)/policies/layout.tsx create mode 100644 src/app/(app)/policies/page.tsx create mode 100644 src/app/(app)/policies/updates/page.tsx create mode 100644 src/app/(app)/policies/upload/page.tsx create mode 100644 src/app/(app)/processes/[id]/edit/page.tsx create mode 100644 src/app/(app)/processes/[id]/page.tsx create mode 100644 src/app/(app)/processes/layout.tsx create mode 100644 src/app/(app)/processes/new/page.tsx create mode 100644 src/app/(app)/processes/page.tsx create mode 100644 src/app/(app)/review/page.tsx create mode 100644 src/app/(app)/risks/catalog/page.tsx create mode 100644 src/app/(app)/risks/layout.tsx create mode 100644 src/app/(app)/risks/page.tsx create mode 100644 src/app/(app)/settings/incident-intake/page.tsx create mode 100644 src/app/(app)/settings/page.tsx create mode 100644 src/app/(app)/settings/risk-criteria/page.tsx create mode 100644 src/app/(app)/settings/users/page.tsx create mode 100644 src/app/(app)/soa/export/route.ts create mode 100644 src/app/(app)/soa/page.tsx create mode 100644 src/app/(app)/suppliers/layout.tsx create mode 100644 src/app/(app)/suppliers/page.tsx create mode 100644 src/app/(app)/tasks/layout.tsx create mode 100644 src/app/(app)/tasks/page.tsx create mode 100644 src/app/(platform)/admin/[id]/page.tsx create mode 100644 src/app/(platform)/admin/backup/page.tsx create mode 100644 src/app/(platform)/admin/page.tsx create mode 100644 src/app/(platform)/admins/page.tsx create mode 100644 src/app/(platform)/layout.tsx create mode 100644 src/app/(platform)/profile/page.tsx create mode 100644 src/app/(platform)/templates/[locale]/[code]/page.tsx create mode 100644 src/app/(platform)/templates/[locale]/requirements/page.tsx create mode 100644 src/app/(platform)/templates/[locale]/variables/page.tsx create mode 100644 src/app/(platform)/templates/page.tsx create mode 100644 src/app/api/auth/[...nextauth]/route.ts create mode 100644 src/app/api/platform-auth/[...nextauth]/route.ts create mode 100644 src/app/api/platform/backup/download/route.ts create mode 100644 src/app/api/platform/dsgvo/[token]/route.ts create mode 100644 src/app/change-password/page.tsx create mode 100644 src/app/enroll-mfa/page.tsx create mode 100644 src/app/error.tsx create mode 100644 src/app/fonts/open-sans-300.woff2 create mode 100644 src/app/fonts/open-sans-400.woff2 create mode 100644 src/app/fonts/open-sans-600.woff2 create mode 100644 src/app/fonts/open-sans-700.woff2 create mode 100644 src/app/fonts/poppins-300.woff2 create mode 100644 src/app/fonts/poppins-500.woff2 create mode 100644 src/app/fonts/poppins-600.woff2 create mode 100644 src/app/fonts/poppins-700.woff2 create mode 100644 src/app/forgot-password/page.tsx create mode 100644 src/app/globals.css create mode 100644 src/app/invite/page.tsx create mode 100644 src/app/layout.tsx create mode 100644 src/app/login/mfa/page.tsx create mode 100644 src/app/login/page.tsx create mode 100644 src/app/not-found.tsx create mode 100644 src/app/page.tsx create mode 100644 src/app/platform/enroll-mfa/page.tsx create mode 100644 src/app/platform/login/page.tsx create mode 100644 src/app/reset/page.tsx create mode 100644 src/app/select-tenant/page.tsx create mode 100644 src/app/verify-email/page.tsx create mode 100644 src/components/asset-form.tsx create mode 100644 src/components/asset-modals.tsx create mode 100644 src/components/audit-trail.tsx create mode 100644 src/components/auth-recovery-forms.tsx create mode 100644 src/components/backup-admin-panel.tsx create mode 100644 src/components/backup-target-form.tsx create mode 100644 src/components/bia-popup.tsx create mode 100644 src/components/brand/certvia-logo.tsx create mode 100644 src/components/brand/powered-by-gefim.tsx create mode 100644 src/components/brand/tenant-brand.tsx create mode 100644 src/components/dependency-graph.tsx create mode 100644 src/components/filter-tabs.tsx create mode 100644 src/components/force-password-change-form.tsx create mode 100644 src/components/generic-register.tsx create mode 100644 src/components/incident-deadlines.tsx create mode 100644 src/components/incident-modals.tsx create mode 100644 src/components/kanban-board.tsx create mode 100644 src/components/mail-status-panel.tsx create mode 100644 src/components/measure-modals.tsx create mode 100644 src/components/mockup-ui.tsx create mode 100644 src/components/modal.tsx create mode 100644 src/components/nav-link.tsx create mode 100644 src/components/object-review.tsx create mode 100644 src/components/passkey-login-button.tsx create mode 100644 src/components/passkey-manager.tsx create mode 100644 src/components/platform-admin-forms.tsx create mode 100644 src/components/platform-enroll-form.tsx create mode 100644 src/components/policy-domain-view.tsx create mode 100644 src/components/policy-expert-editor.tsx create mode 100644 src/components/policy-modals.tsx create mode 100644 src/components/policy-registers.tsx create mode 100644 src/components/process-form.tsx create mode 100644 src/components/process-modals.tsx create mode 100644 src/components/project-modals.tsx create mode 100644 src/components/risk-modals.tsx create mode 100644 src/components/role-manager.tsx create mode 100644 src/components/segmented-rating.tsx create mode 100644 src/components/service-modals.tsx create mode 100644 src/components/software-modals.tsx create mode 100644 src/components/supplier-cockpit.tsx create mode 100644 src/components/supplier-modals.tsx create mode 100644 src/components/task-modals.tsx create mode 100644 src/components/tenant-mfa-enroll-form.tsx create mode 100644 src/components/tenant-recovery-regen-form.tsx create mode 100644 src/components/tenant-switcher.tsx create mode 100644 src/components/ui-locale-switcher.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/separator.tsx create mode 100644 src/components/ui/table.tsx create mode 100644 src/components/ui/tabs.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/components/user-forms.tsx create mode 100644 src/components/user-table.tsx create mode 100644 src/i18n/request.ts create mode 100644 src/lib/assessment.ts create mode 100644 src/lib/asset-labels.ts create mode 100644 src/lib/audit-readiness/activation.ts create mode 100644 src/lib/brand.ts create mode 100644 src/lib/control-domain.ts create mode 100644 src/lib/control-specs-iso.ts create mode 100644 src/lib/control-titles-iso.ts create mode 100644 src/lib/control-titles.ts create mode 100644 src/lib/document-brand.ts create mode 100644 src/lib/email-brand.ts create mode 100644 src/lib/export/vda-isa.ts create mode 100644 src/lib/ft-rules.ts create mode 100644 src/lib/gap-consolidation.ts create mode 100644 src/lib/incident-deadlines.ts create mode 100644 src/lib/incident-export.ts create mode 100644 src/lib/incident-report-html.ts create mode 100644 src/lib/incident-severity.ts create mode 100644 src/lib/incident.ts create mode 100644 src/lib/isa-controls.ts create mode 100644 src/lib/isb-bestellung.ts create mode 100644 src/lib/iso-isa-crosswalk.ts create mode 100644 src/lib/levels.ts create mode 100644 src/lib/maturity.ts create mode 100644 src/lib/measure.ts create mode 100644 src/lib/mfa-policy.ts create mode 100644 src/lib/modules.ts create mode 100644 src/lib/normalize-asset.ts create mode 100644 src/lib/object-review.ts create mode 100644 src/lib/onboarding/facts.ts create mode 100644 src/lib/onboarding/functions.ts create mode 100644 src/lib/onboarding/questions.ts create mode 100644 src/lib/onboarding/register-steps.ts create mode 100644 src/lib/onboarding/registry.ts create mode 100644 src/lib/onboarding/state.ts create mode 100644 src/lib/password-policy.ts create mode 100644 src/lib/policy-render.ts create mode 100644 src/lib/policy-titles.ts create mode 100644 src/lib/policy-variables.ts create mode 100644 src/lib/readiness.ts create mode 100644 src/lib/review-cycle.ts create mode 100644 src/lib/risk.ts create mode 100644 src/lib/rules/dsl.ts create mode 100644 src/lib/rules/engine.ts create mode 100644 src/lib/rules/feature-rules.ts create mode 100644 src/lib/scope-filter.ts create mode 100644 src/lib/soa.ts create mode 100644 src/lib/supplier-include.ts create mode 100644 src/lib/supplier.ts create mode 100644 src/lib/task-triggers.ts create mode 100644 src/lib/tasks.ts create mode 100644 src/lib/utils.ts create mode 100644 src/proxy.ts create mode 100644 src/server/action-error.ts create mode 100644 src/server/action-guard.ts create mode 100644 src/server/actions/account.ts create mode 100644 src/server/actions/admin.ts create mode 100644 src/server/actions/assets.ts create mode 100644 src/server/actions/audit-evidence.ts create mode 100644 src/server/actions/audits.ts create mode 100644 src/server/actions/auth-recovery.ts create mode 100644 src/server/actions/backup-admin.ts create mode 100644 src/server/actions/backup-settings.ts create mode 100644 src/server/actions/control-descriptions.ts create mode 100644 src/server/actions/gap.ts create mode 100644 src/server/actions/hints.ts create mode 100644 src/server/actions/incident-intake-admin.ts create mode 100644 src/server/actions/incident-intake.ts create mode 100644 src/server/actions/incidents.ts create mode 100644 src/server/actions/mail.ts create mode 100644 src/server/actions/measures.ts create mode 100644 src/server/actions/onboarding-facts.ts create mode 100644 src/server/actions/onboarding-steps.ts create mode 100644 src/server/actions/onboarding-team.ts create mode 100644 src/server/actions/onboarding.ts create mode 100644 src/server/actions/platform-admins.ts create mode 100644 src/server/actions/platform-users.ts create mode 100644 src/server/actions/platform.ts create mode 100644 src/server/actions/policies.ts create mode 100644 src/server/actions/policy-control.ts create mode 100644 src/server/actions/policy-package.ts create mode 100644 src/server/actions/policy-templates.ts create mode 100644 src/server/actions/policy-upload.ts create mode 100644 src/server/actions/processes.ts create mode 100644 src/server/actions/projects.ts create mode 100644 src/server/actions/register.ts create mode 100644 src/server/actions/review.ts create mode 100644 src/server/actions/risk-catalog.ts create mode 100644 src/server/actions/risks.ts create mode 100644 src/server/actions/services.ts create mode 100644 src/server/actions/soa-entries.ts create mode 100644 src/server/actions/soa.ts create mode 100644 src/server/actions/software.ts create mode 100644 src/server/actions/structure.ts create mode 100644 src/server/actions/suppliers.ts create mode 100644 src/server/actions/tasks.ts create mode 100644 src/server/actions/tenant-settings.ts create mode 100644 src/server/actions/tenant-switch.ts create mode 100644 src/server/actions/tenant-users.ts create mode 100644 src/server/actions/webauthn.ts create mode 100644 src/server/ai/client.ts create mode 100644 src/server/ai/draft-control-description.ts create mode 100644 src/server/assessment-level.ts create mode 100644 src/server/assessment.ts create mode 100644 src/server/audit.ts create mode 100644 src/server/auth-selfservice.ts create mode 100644 src/server/auth-token.ts create mode 100644 src/server/auth.ts create mode 100644 src/server/backup/crypto.ts create mode 100644 src/server/backup/dsgvo-zip.ts create mode 100644 src/server/backup/export.ts create mode 100644 src/server/backup/index.ts create mode 100644 src/server/backup/job.ts create mode 100644 src/server/backup/ops.ts create mode 100644 src/server/backup/queue.ts create mode 100644 src/server/backup/restore-confirm.ts create mode 100644 src/server/backup/restore.ts create mode 100644 src/server/backup/serialization.ts create mode 100644 src/server/backup/topology.ts create mode 100644 src/server/backup/worker.ts create mode 100644 src/server/backup/zip.ts create mode 100644 src/server/control-descriptions-context.ts create mode 100644 src/server/control-domain.ts create mode 100644 src/server/db.ts create mode 100644 src/server/dependency-graph.ts create mode 100644 src/server/dsgvo/deletion.ts create mode 100644 src/server/dsgvo/export.ts create mode 100644 src/server/dsgvo/pii-fields.ts create mode 100644 src/server/dsgvo/tombstone.ts create mode 100644 src/server/env.ts create mode 100644 src/server/export-context.ts create mode 100644 src/server/export/incident-xlsx.ts create mode 100644 src/server/export/soa-xlsx.ts create mode 100644 src/server/export/vda-isa-xlsx.ts create mode 100644 src/server/gap-context.ts create mode 100644 src/server/incident-export-context.ts create mode 100644 src/server/incident-inbound/parse.ts create mode 100644 src/server/incident-inbound/process.ts create mode 100644 src/server/incident-inbound/route.ts create mode 100644 src/server/incident-refno.ts create mode 100644 src/server/iso-hints.ts create mode 100644 src/server/login-ticket.ts create mode 100644 src/server/mail/config.ts create mode 100644 src/server/mail/deliver.ts create mode 100644 src/server/mail/incident-notifications.ts create mode 100644 src/server/mail/job.ts create mode 100644 src/server/mail/notifications.ts create mode 100644 src/server/mail/provider-smtp.ts create mode 100644 src/server/mail/provider.ts create mode 100644 src/server/mail/queue.ts create mode 100644 src/server/mail/service.ts create mode 100644 src/server/mail/templates.ts create mode 100644 src/server/mail/worker.ts create mode 100644 src/server/mfa.ts create mode 100644 src/server/modules.ts create mode 100644 src/server/object-review.ts create mode 100644 src/server/password.ts create mode 100644 src/server/platform-auth.ts create mode 100644 src/server/platform-settings.ts create mode 100644 src/server/policies/derive-domains.ts create mode 100644 src/server/provision.ts create mode 100644 src/server/rate-limit.ts create mode 100644 src/server/rbac.ts create mode 100644 src/server/risk-calc.ts create mode 100644 src/server/roles.ts create mode 100644 src/server/secret-crypto.ts create mode 100644 src/server/sessions.ts create mode 100644 src/server/soa-context.ts create mode 100644 src/server/soa-statement.ts create mode 100644 src/server/storage/adapter.ts create mode 100644 src/server/storage/backup-store.ts create mode 100644 src/server/task-sync.ts create mode 100644 src/server/task-visibility.ts create mode 100644 src/server/webauthn.ts create mode 100644 src/types/next-auth.d.ts create mode 100644 tsconfig.json create mode 100644 types/mailparser.d.ts diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..c34d187 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "isms-dev", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "port": 3000 + } + ] +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cfe3aa4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +node_modules +.next +# Lokale Env-Dateien NICHT ins Image kopieren (Secrets); Build nutzt Build-ENV/Args +.env +.env.* +!.env.example +!.env.coolify.example +*.log +Dockerfile* +docker-compose*.yml +.dockerignore diff --git a/.env.coolify.example b/.env.coolify.example new file mode 100644 index 0000000..f145496 --- /dev/null +++ b/.env.coolify.example @@ -0,0 +1,72 @@ +# Referenz für die Coolify-Environment-Variablen (Testserver, intern). +# ECHTE Secrets NUR in Coolify eintragen — diese Datei enthält nur Platzhalter. +# In Coolify: Ressource -> Environment Variables (Bulk-Paste möglich). +# Hostnamen sind die Compose-Service-Namen (postgres/redis/garage), NICHT localhost. + +# --- Datenbank (Service "postgres") --- +POSTGRES_USER=isms +POSTGRES_PASSWORD=CHANGE_ME_db_password +POSTGRES_DB=isms +DATABASE_URL=postgresql://isms:CHANGE_ME_db_password@postgres:5432/isms?schema=public + +# --- Redis (Service "redis") --- +# F-18: Redis läuft mit requirepass. NUR REDIS_PASSWORD setzen — REDIS_URL wird in der +# docker-compose.coolify.yml daraus abgeleitet (redis://:${REDIS_PASSWORD}@redis:6379) +# und ist deshalb NICHT separat zu setzen (in Coolify sonst als „managed" gesperrt). +REDIS_PASSWORD=CHANGE_ME_redis_password + +# --- Objektspeicher (Service "garage", S3-kompatibel) --- +# Garage ersetzt MinIO (Community EOL). Buckets/Keys legt NICHT die S3-API an, sondern +# der Init-Job "garage-provision" (Admin-API). S3_ACCESS_KEY/S3_SECRET_KEY sind der +# Garage-Key, den dieser Job importiert (App-Env == Garage). Garage erzwingt das Format: +# S3_ACCESS_KEY = "GK" + 24 Hex -> echo "GK$(openssl rand -hex 12)" +# S3_SECRET_KEY = 64 Hex -> openssl rand -hex 32 +S3_ENDPOINT=http://garage:3900 +S3_ACCESS_KEY=GK000000000000000000000000 +S3_SECRET_KEY=CHANGE_ME_openssl_rand_hex_32 +S3_BUCKET=isms-documents +S3_REGION=us-east-1 +# Garage-Secrets: der Daemon liest sie aus der Env (NICHT in deploy/garage.toml). +# In Coolify LITERAL setzen, NICHT via ${...} referenzieren (Interpolationsfalle). +# GARAGE_RPC_SECRET: openssl rand -hex 32 +# GARAGE_ADMIN_TOKEN: openssl rand -hex 32 +GARAGE_RPC_SECRET=CHANGE_ME_openssl_rand_hex_32 +GARAGE_ADMIN_TOKEN=CHANGE_ME_openssl_rand_hex_32 +# Optional: Single-Node-Layout (nominal). Zone/Kapazität nur bei Bedarf überschreiben. +# GARAGE_ZONE=dc1 +# GARAGE_CAPACITY_BYTES=100000000000 + +# --- Backup-Zielspeicher (optional) --- +# Ziel der Backup-/DSGVO-Artefakte ist im Betreiber-Portal (/admin/backup) waehlbar +# (Lokal/S3) und wird verschluesselt in der DB gehalten. Praezedenz: DB-Config → +# Env (S3_*/BACKUP_LOCAL_DIR) → lokaler Default. Sobald im Portal gespeichert, hat die +# DB-Config Vorrang. Fuer „Lokal" mountet die Compose-Datei das persistente Volume +# `backups` auf /app/.backups (app + backup-worker) — Pfad hier NICHT aendern, ausser +# der Mount wird angepasst. +BACKUP_LOCAL_DIR=/app/.backups + +# --- Auth (NextAuth) --- +# AUTH_SECRET: openssl rand -base64 32 +# AUTH_URL: exakt die Coolify-Domain des app-Service (http:// für intern) +AUTH_SECRET=CHANGE_ME_openssl_rand_base64_32 +# PASSWORD_PEPPER (Härtung §1): openssl rand -hex 32 — frisch je Umgebung, NICHT rotierbar, nie ins Artefakt. +PASSWORD_PEPPER=CHANGE_ME_openssl_rand_hex_32 +AUTH_URL=http://REPLACE-WITH-COOLIFY-SSLIP-DOMAIN +# Hinter Reverse-Proxy (Coolify/Traefik) für Auth.js v5 zwingend, sonst UntrustedHost: +AUTH_TRUST_HOST=true + +# --- Demo-Seed (NUR Testserver!) --- +# true => migrate-Job legt nach der Migration den Demo-Mandanten + Nutzer an +# (admin@demo.example / Demo1234!). In Produktion NICHT setzen / auf false lassen. +RUN_DEMO_SEED=true + +# --- KI-Provider (optional, aktuell ungenutzt) --- +AI_PROVIDER=anthropic +AI_API_KEY= + +# --- E-Mail (optional, im Test ungenutzt) --- +SMTP_HOST= +SMTP_PORT=1025 +SMTP_USER= +SMTP_PASSWORD= +SMTP_FROM=isms@example.com diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5ce0270 --- /dev/null +++ b/.env.example @@ -0,0 +1,90 @@ +# --- Datenbank --- +POSTGRES_USER=isms +POSTGRES_PASSWORD=isms +POSTGRES_DB=isms +DATABASE_URL=postgresql://isms:isms@localhost:5432/isms?schema=public + +# --- Row Level Security (F-04) — lokal AUS (Owner-Betrieb) --- +# Lokal bleibt RLS aus: Der Owner isms ist Superuser/BYPASSRLS und sieht trotz +# FORCE alle Daten. Zum scharfen Testen die beiden Zeilen aktivieren (die Rolle +# isms_app zuvor mit LOGIN+Passwort versehen, s. scripts/test-rls-enforcement.ts): +# RLS_ENFORCED=true +# RLS_DATABASE_URL=postgresql://isms_app:isms_app_local@localhost:5432/isms?schema=public + +# --- Redis (BullMQ) --- +# F-18: Redis läuft mit requirepass. REDIS_PASSWORD muss zum docker-compose-Default +# passen; das Passwort steht zusätzlich in der REDIS_URL (redis://:@host:port). +REDIS_PASSWORD=isms-redis +REDIS_URL=redis://:isms-redis@localhost:6379 + +# --- Objektspeicher (Garage / S3-kompatibel) --- +# Sind alle vier S3_*-Pflichtvariablen gesetzt, nutzt der Storage-Adapter das echte +# S3-Backend (Byte-Speicherung + Download-Route /files/). Fehlt eine davon, faellt +# der Adapter auf den Stub zurueck (nur Metadaten, keine Bytes) - kein Crash. +# Der Bucket wird NICHT automatisch angelegt (Garage bedient kein S3-CreateBucket): er +# muss vorab provisioniert sein (Compose-Service "garage-provision"). Fehlt er, wirft der +# Adapter einen sprechenden Konfigurationsfehler. +# Garage erzwingt das Key-Format: S3_ACCESS_KEY = "GK" + 24 Hex, S3_SECRET_KEY = 64 Hex. +S3_ENDPOINT=http://localhost:3900 +S3_ACCESS_KEY=GKdead0000beef0000cafe0000 +S3_SECRET_KEY=0000000000000000000000000000000000000000000000000000000000000001 +S3_BUCKET=isms-documents +# Region beidseitig us-east-1 (deckt sich mit garage.toml s3_region). forcePathStyle ist +# im Code fest gesetzt - Garage bedient ausschliesslich Path-Style. +S3_REGION=us-east-1 + +# Garage-Daemon-Secrets (der Daemon liest sie aus der Env, NICHT aus deploy/garage.toml). +# Lokale Dev-Werte (unkritisch, nur localhost). Fuer eigene Stacks frisch erzeugen: +# openssl rand -hex 32 +GARAGE_RPC_SECRET=0000000000000000000000000000000000000000000000000000000000000002 +GARAGE_ADMIN_TOKEN=0000000000000000000000000000000000000000000000000000000000000003 + +# --- Backup-Zielspeicher (optional) --- +# Lane „Konfigurierbarer Backup-Zielspeicher": das Ziel der Backup-/DSGVO-Artefakte ist +# jetzt im Betreiber-Portal (/admin/backup) waehlbar (Lokal/S3) und wird in der DB +# gespeichert. Praezedenz zur Laufzeit: DB-Config → diese Env-Vars → lokaler Default. +# Ohne DB-Config gelten weiter S3_* (siehe oben) bzw. — falls unvollstaendig — der +# lokale Ordner unten. HINWEIS: sobald im Portal ein Ziel gespeichert wird, hat die +# DB-Config Vorrang vor S3_*/BACKUP_LOCAL_DIR. +# Lokaler Ordner fuer Backup-Artefakte (Dev: relativ zum cwd). In Prod auf ein +# gemountetes, persistentes Volume zeigen lassen (sonst beim Redeploy fluechtig). +BACKUP_LOCAL_DIR=.backups + +# --- Auth --- +AUTH_SECRET=change-me-generate-with-openssl-rand-base64-32 +# PASSWORD_PEPPER (Härtung §1): 32-Byte hex, pro Umgebung eindeutig. openssl rand -hex 32 +# ⚠ NICHT rotierbar ohne Passwort-Reset für alle; NICHT aus AUTH_SECRET ableiten; NICHT ins Backup-Artefakt. +PASSWORD_PEPPER=change-me-openssl-rand-hex-32 +AUTH_URL=http://localhost:3000 + +# --- KI-Provider (anthropic | openai) --- +AI_PROVIDER=anthropic +AI_API_KEY= + +# --- Anthropic (KI-Entwurf Control-Beschreibungen, Audit-Vorbereitung) --- +# Ohne ANTHROPIC_API_KEY ist die KI-Anbindung deaktiviert (graceful degradation): +# kein Entwurf, Status bleibt „manuell zu erfassen", die UI funktioniert weiter. +ANTHROPIC_API_KEY= +# Optionale Modell-ID; Default: claude-opus-5 +ANTHROPIC_MODEL=claude-opus-5 + +# --- E-Mail / SMTP (SEC1) --- +# Dev: Mailpit oder Mailhog (docker-compose Service `mailhog`, SMTP auf 1025, +# Weboberflaeche auf 8025). Gegen localhost wird TLS bewusst nicht erzwungen. +# Prod: dedizierte Absenderdomain mit SPF, DKIM und DMARC — Vorbedingung vor +# dem ersten Produktivversand. Secrets ausschliesslich aus dem Secret-Store. +SMTP_HOST=localhost +SMTP_PORT=1025 +# true = implizites TLS (Port 465), false = STARTTLS (587). Ohne Angabe wird +# aus dem Port abgeleitet. +SMTP_SECURE=false +SMTP_USER= +SMTP_PASSWORD= +# Absenderadresse und Anzeigename. MAIL_FROM/MAIL_FROM_NAME werden als Alias +# ebenfalls akzeptiert. +SMTP_FROM=no-reply@certvia.de +MAIL_FROM_NAME=Certvia +# Optionale Antwortadresse (sonst keine Reply-To-Kopfzeile). +MAIL_REPLY_TO= +# Basis fuer absolute Links in Mails. Faellt auf AUTH_URL zurueck. +APP_BASE_URL=http://localhost:3000 diff --git a/.env.prod.example b/.env.prod.example new file mode 100644 index 0000000..6447cc5 --- /dev/null +++ b/.env.prod.example @@ -0,0 +1,76 @@ +# Referenz für die PRODUKTIV-Env-Variablen (Contabo-VPS + Coolify). +# ECHTE Secrets NUR in Coolify eintragen — diese Datei enthält nur Platzhalter. +# Unterschiede zum Testserver: HTTPS-AUTH_URL, KEIN Demo-Seed, stattdessen Bootstrap-Admin. + +# --- Datenbank (Service "postgres") --- +POSTGRES_USER=isms +POSTGRES_PASSWORD=CHANGE_ME_starkes_db_passwort +POSTGRES_DB=isms +DATABASE_URL=postgresql://isms:CHANGE_ME_starkes_db_passwort@postgres:5432/isms?schema=public + +# --- Row Level Security scharfschalten (F-04) --- +# RLS_ENFORCED=true → die App verbindet sich als eingeschränkte Rolle isms_app +# (NOBYPASSRLS) und setzt app.tenant_id pro Transaktion; FORCE ROW LEVEL SECURITY +# macht die Policies dann scharf. Ist der Kontext nicht gesetzt, sieht isms_app +# NULL Zeilen — daher NUR mit korrekt gesetztem RLS_DATABASE_URL einschalten. +# WICHTIG: Die Owner-/Migrate-Rolle in DATABASE_URL MUSS BYPASSRLS/Superuser sein +# (Migrationen, Seed und der mandantenübergreifende Login-Lookup laufen darüber), +# sonst sähe der Login keine Nutzer. isms_app in Prod EINMALIG mit LOGIN + starkem +# Passwort versehen: ALTER ROLE isms_app WITH LOGIN PASSWORD ''; +RLS_ENFORCED=true +RLS_DATABASE_URL=postgresql://isms_app:CHANGE_ME_starkes_isms_app_passwort@postgres:5432/isms?schema=public + +# --- Redis --- +# F-18: Redis läuft mit requirepass. REDIS_PASSWORD setzen (stark!) und identisch +# in die REDIS_URL einsetzen (redis://:@redis:6379). +REDIS_PASSWORD=CHANGE_ME_starkes_redis_passwort +REDIS_URL=redis://:CHANGE_ME_starkes_redis_passwort@redis:6379 + +# --- Objektspeicher (MinIO) — S3_* muss zu MINIO_ROOT_* passen --- +S3_ENDPOINT=http://minio:9000 +S3_ACCESS_KEY=isms +S3_SECRET_KEY=CHANGE_ME_starkes_minio_passwort +S3_BUCKET=isms-documents +MINIO_ROOT_USER=isms +MINIO_ROOT_PASSWORD=CHANGE_ME_starkes_minio_passwort + +# --- Backup-Zielspeicher (optional) --- +# Ziel der Backup-/DSGVO-Artefakte ist im Betreiber-Portal (/admin/backup) waehlbar +# (Lokal/S3) und wird verschluesselt in der DB gehalten. Praezedenz: DB-Config → +# Env (S3_*/BACKUP_LOCAL_DIR) → lokaler Default. Sobald im Portal gespeichert, hat +# die DB-Config Vorrang. Fuer „Lokal" auf ein gemountetes, persistentes Volume zeigen. +BACKUP_LOCAL_DIR=/app/.backups + +# --- Auth (NextAuth) — Produktiv über HTTPS --- +# AUTH_SECRET: openssl rand -base64 32 (frisch, NICHT der Testwert) +AUTH_SECRET=CHANGE_ME_openssl_rand_base64_32 +# PASSWORD_PEPPER (Härtung §1): openssl rand -hex 32 — frisch je Umgebung, NICHT rotierbar, nie ins Artefakt. +PASSWORD_PEPPER=CHANGE_ME_openssl_rand_hex_32 +AUTH_URL=https://app.certvia.de +# AUTH_TRUST_HOST ist im Compose fest auf true (hinter dem Coolify-Proxy) — nicht nötig. + +# --- KI-Provider (optional) --- +AI_PROVIDER=anthropic +AI_API_KEY= + +# --- E-Mail (produktives SMTP-Relay, sobald Einladungs-/Mailflow aktiv) --- +SMTP_HOST= +SMTP_PORT=587 +SMTP_USER= +SMTP_PASSWORD= +SMTP_FROM=noreply@certvia.de + +# --- Demo-Seed: in PROD AUS lassen! --- +RUN_DEMO_SEED=false + +# --- Erst-Superadmin-Bootstrap (statt Demo-Seed) --- +# Beim ersten Deploy true setzen -> migrate-Job legt Admin + Mandant an (idempotent). +# Danach kann true bleiben (tut nichts, wenn der Admin existiert) oder auf false. +BOOTSTRAP_ADMIN=true +BOOTSTRAP_ADMIN_EMAIL=admin@certvia.de +BOOTSTRAP_ADMIN_PASSWORD=CHANGE_ME_initiales_admin_passwort +BOOTSTRAP_ADMIN_NAME=Certvia Admin +BOOTSTRAP_TENANT_NAME=Certvia +BOOTSTRAP_TENANT_SLUG=certvia +BOOTSTRAP_TENANT_SHORT=Certvia +BOOTSTRAP_TENANT_SECTOR= diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..8a22164 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,116 @@ +# CI-Pipeline (Gitea Actions — GitHub-Actions-kompatibel). +# +# WICHTIG: Braucht einen aktivierten Gitea-Actions-Runner (git.certvia.de -> +# Settings -> Actions -> Runners). Ohne registrierten Runner wird dieser Workflow +# NICHT ausgeführt (er schlägt nicht fehl, er läuft schlicht nicht an). +# Inhaltlich identisch zu .github/workflows/ci.yml (Spiegel für Nicht-Gitea-Remotes). +name: CI + +on: + push: + branches: ["main", "dev", "dev-*"] + pull_request: + branches: ["main", "dev", "dev-*"] + +jobs: + build-and-check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Node 22 einrichten + uses: actions/setup-node@v4 + with: + node-version: "22.14.0" + + # npm 11 pinnen: Das committete Lockfile wurde mit npm 11 erzeugt; node 22.14 + # bringt npm 10.9.2 mit, das next@16.2.12 -> @swc/helpers anders auflöst und + # `npm ci` sonst mit "out of sync" abbricht (siehe Dockerfile). + - name: npm 11 pinnen + run: npm i -g npm@11.19.0 + + - name: Abhängigkeiten installieren (Lockfile bindend) + run: npm ci --include=optional --no-audit --no-fund + + - name: Prisma Client generieren + # Platzhalter-URL nur fürs Laden von prisma.config.ts — keine echte DB-Verbindung. + env: + DATABASE_URL: "postgresql://build:build@localhost:5432/build?schema=public" + run: npx prisma generate + + - name: Typprüfung (tsc --noEmit) + run: npx tsc --noEmit + + - name: Lint + run: npm run lint + + - name: Build + env: + DATABASE_URL: "postgresql://build:build@localhost:5432/build?schema=public" + run: npm run build + + audit: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Node 22 einrichten + uses: actions/setup-node@v4 + with: + node-version: "22.14.0" + + - name: npm 11 pinnen + run: npm i -g npm@11.19.0 + + - name: Abhängigkeiten installieren + run: npm ci --include=optional --no-audit --no-fund + + # HARTES Gate: nur Produktions-Abhängigkeiten, ab "high" bricht der Build. + # Bewusst --omit=dev, weil die bekannten High-Findings (F-12) in der + # Build-/Lint-Toolchain (devDependencies) liegen und die Auslieferung nicht + # gefährden. Der Produktionsbaum ist aktuell frei von high/critical -> grün. + - name: npm audit (Gate, prod-only, high+) + run: npm audit --omit=dev --audit-level=high + + # INFORMATIV: voller Lauf inkl. devDependencies. Bricht den Build NICHT + # (continue-on-error), macht die dev-only-Befunde aber im Log sichtbar. + - name: npm audit (informativ, voller Baum) + continue-on-error: true + run: npm audit --audit-level=high + + sbom: + # Optionaler Schritt: erzeugt eine Software Bill of Materials (CycloneDX) und + # legt sie als Build-Artefakt ab. Für Supply-Chain-Nachvollziehbarkeit (F-11). + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Node 22 einrichten + uses: actions/setup-node@v4 + with: + node-version: "22.14.0" + + - name: npm 11 pinnen + run: npm i -g npm@11.19.0 + + - name: Abhängigkeiten installieren + run: npm ci --include=optional --no-audit --no-fund + + # Hinweis: `npm sbom` validiert den installierten Baum streng. Solange das + # Lockfile die @swc/helpers-Inkonsistenz trägt (siehe Dockerfile / Folgeänderung + # der Dependency-Lane), bricht der Schritt mit ESBOMPROBLEMS ab — daher + # continue-on-error. Alternative ohne npm-Baum-Validierung: Syft gegen das + # gebaute Image (siehe docs/DEPLOY-PROD-CONTABO.md, Abschnitt SBOM). + - name: SBOM erzeugen (CycloneDX) + continue-on-error: true + run: npm sbom --sbom-format cyclonedx --omit dev > sbom.cyclonedx.json + + - name: SBOM als Artefakt ablegen + continue-on-error: true + uses: actions/upload-artifact@v4 + with: + name: sbom-cyclonedx + path: sbom.cyclonedx.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0cd4ea9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,113 @@ +# CI-Pipeline — Spiegel von .gitea/workflows/ci.yml (identischer Job-Inhalt). +# Primäres Remote ist Gitea (git.certvia.de); diese Datei greift nur, falls das +# Repo (auch) auf einem GitHub-Actions-Remote gespiegelt wird. +# +# WICHTIG: Braucht einen aktivierten Actions-Runner. Ohne Runner läuft der +# Workflow nicht an (kein Fehlschlag, nur kein Lauf). +name: CI + +on: + push: + branches: ["main", "dev", "dev-*"] + pull_request: + branches: ["main", "dev", "dev-*"] + +jobs: + build-and-check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Node 22 einrichten + uses: actions/setup-node@v4 + with: + node-version: "22.14.0" + + # npm 11 pinnen: Das committete Lockfile wurde mit npm 11 erzeugt; node 22.14 + # bringt npm 10.9.2 mit, das next@16.2.12 -> @swc/helpers anders auflöst und + # `npm ci` sonst mit "out of sync" abbricht (siehe Dockerfile). + - name: npm 11 pinnen + run: npm i -g npm@11.19.0 + + - name: Abhängigkeiten installieren (Lockfile bindend) + run: npm ci --include=optional --no-audit --no-fund + + - name: Prisma Client generieren + env: + DATABASE_URL: "postgresql://build:build@localhost:5432/build?schema=public" + run: npx prisma generate + + - name: Typprüfung (tsc --noEmit) + run: npx tsc --noEmit + + - name: Lint + run: npm run lint + + - name: Build + env: + DATABASE_URL: "postgresql://build:build@localhost:5432/build?schema=public" + run: npm run build + + audit: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Node 22 einrichten + uses: actions/setup-node@v4 + with: + node-version: "22.14.0" + + - name: npm 11 pinnen + run: npm i -g npm@11.19.0 + + - name: Abhängigkeiten installieren + run: npm ci --include=optional --no-audit --no-fund + + # HARTES Gate: nur Produktions-Abhängigkeiten, ab "high" bricht der Build. + # Bewusst --omit=dev, weil die bekannten High-Findings (F-12) in der + # Build-/Lint-Toolchain (devDependencies) liegen und die Auslieferung nicht + # gefährden. Der Produktionsbaum ist aktuell frei von high/critical -> grün. + - name: npm audit (Gate, prod-only, high+) + run: npm audit --omit=dev --audit-level=high + + # INFORMATIV: voller Lauf inkl. devDependencies. Bricht den Build NICHT. + - name: npm audit (informativ, voller Baum) + continue-on-error: true + run: npm audit --audit-level=high + + sbom: + # Optionaler Schritt: erzeugt eine Software Bill of Materials (CycloneDX). + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Node 22 einrichten + uses: actions/setup-node@v4 + with: + node-version: "22.14.0" + + - name: npm 11 pinnen + run: npm i -g npm@11.19.0 + + - name: Abhängigkeiten installieren + run: npm ci --include=optional --no-audit --no-fund + + # Hinweis: `npm sbom` validiert den installierten Baum streng. Solange das + # Lockfile die @swc/helpers-Inkonsistenz trägt (siehe Dockerfile / Folgeänderung + # der Dependency-Lane), bricht der Schritt mit ESBOMPROBLEMS ab — daher + # continue-on-error. Alternative ohne npm-Baum-Validierung: Syft gegen das + # gebaute Image (siehe docs/DEPLOY-PROD-CONTABO.md, Abschnitt SBOM). + - name: SBOM erzeugen (CycloneDX) + continue-on-error: true + run: npm sbom --sbom-format cyclonedx --omit dev > sbom.cyclonedx.json + + - name: SBOM als Artefakt ablegen + continue-on-error: true + uses: actions/upload-artifact@v4 + with: + name: sbom-cyclonedx + path: sbom.cyclonedx.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95bf52d --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* +!.env.example +!.env.coolify.example +!.env.prod.example + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Backup-Lane: lokaler Artefakt-Store (S3/MinIO-Fallback) +.backups/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..fc05a5d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,40 @@ + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + + +# ISMS-Tool — Projektregeln + +Multi-Tenant-SaaS für Informationssicherheits-Managementsysteme (ISO/IEC 27001:2022, TISAX/VDA-ISA 6.0). + +**Maßgebliche Spezifikation: [docs/SPEC.md](docs/SPEC.md)** — Architektur, Datenmodell, Module, Rollen, Akzeptanzkriterien. UI-Referenz: [docs/ISMS-Prototyp-GEFIM.html](docs/ISMS-Prototyp-GEFIM.html) (Orientierung für Navigation/Layout; fachlich gilt die Spec, die über das Mockup hinausgeht). + +## Eiserne Regeln + +1. **Mandanten-Isolation:** Kein DB-Zugriff an Prisma vorbei, kein Query ohne Tenant-Kontext. Fachliche Tabellen tragen `tenant_id`; Zugriff nur über den Tenant-Guard (`src/server/db.ts`), zusätzlich Postgres RLS. +2. **RBAC serverseitig:** Jede Mutation/Query prüft Permissions am Server (`asset:read`, `risk:write`, …). UI-Ausblenden ist nur Komfort, nie Sicherheit. +3. **Audit-Log:** Jede schreibende Aktion erzeugt einen `AuditLog`-Eintrag (before/after). +4. **i18n:** Keine hartkodierten UI-Texte — alle Strings über den Message-Katalog (`de` default, `en` vorbereitet). +5. **Lizenz:** Keine ISO-Normtexte oder VDA-ISA-Kataloginhalte einchecken — nur Control-Referenzen/Titel; VDA-ISA-Inhalte kommen per Kunden-Import (`ISA6-EN.xlsx`). + +## Stack & Konventionen + +- Next.js (App Router) + TypeScript, Tailwind CSS 4, shadcn/ui, dnd-kit, Recharts. +- Prisma + PostgreSQL 16 (pgvector), BullMQ + Redis (Worker), MinIO (S3), Auth.js (Credentials, Argon2id). +- Tests: Vitest (Unit), Playwright (E2E). `npm run lint` und `npm run build` müssen vor jedem Commit grün sein. +- Sprache: UI und Fachbegriffe Deutsch; Code (Bezeichner, Kommentare) Englisch. + +## Offene Härtungspunkte (Iteration 8) + +- RLS scharfschalten: App-Verbindung auf DB-Rolle `isms_app` umstellen und `app.tenant_id` pro Transaktion setzen (Policies existieren bereits, siehe Migration `row_level_security`). +- TOTP-2FA (Schema-Feld `mfa_secret` ist vorbereitet). +- Rollenänderungen wirken erst beim nächsten Login (Permissions liegen im JWT). + +## Entwicklung + +```bash +docker compose up -d postgres redis minio # Infrastruktur +npx prisma migrate dev # Migrationen +npm run dev # App auf :3000 +``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b3140e3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,121 @@ +# ISMS-Tool — Next.js App (Multi-Stage-Build) +# +# Base-Image: node:22-slim (Debian/glibc) statt node:22-alpine (musl). +# Begründung (F-11): Mit einem glibc-Base greifen die im Lockfile hinterlegten +# plattformspezifischen Optional-Deps (lightningcss/@tailwindcss/oxide *-linux-*-gnu, +# ebenso die glibc-Prebuilds von @node-rs/argon2 und sharp) zuverlässig. Dadurch +# funktioniert `npm ci` (Lockfile bindend, reproduzierbar) OHNE Lockfile-Änderung — +# das package-lock.json enthält bereits alle vier Linux-Varianten (x64/arm64 × gnu/musl). +# Der frühere Kommentar ("npm install nötig wegen fehlender musl-Binaries") entfällt damit. +FROM node:22.14.0-slim AS deps +WORKDIR /app +# openssl/ca-certificates werden von Prisma (Engine) und für TLS beim npm-Install benötigt. +RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \ + && rm -rf /var/lib/apt/lists/* +# npm auf 11.x pinnen: Das committete package-lock.json wurde mit npm 11 erzeugt. +# node:22.14.0 bringt npm 10.9.2 mit, das next@16.2.12 -> @swc/helpers ANDERS auflöst +# (erwartet 0.5.23, Lock hält 0.5.15) und `npm ci` daher mit "out of sync" abbricht. +# Der Resolver-Gleichstand (npm 11) macht `npm ci` grün OHNE Lockfile-Änderung. +RUN npm i -g npm@11.19.0 +COPY package.json package-lock.json ./ +COPY prisma ./prisma +# npm ci: installiert exakt die im Lockfile gepinnten Versionen (Supply-Chain-Integrität, +# reproduzierbare Builds). --include=optional stellt sicher, dass die plattformspezifischen +# Native-Binaries für das Zielimage (linux/glibc) mitkommen. +RUN npm ci --include=optional --no-audit --no-fund + +# --- Build-Stage: kompletter Next.js-Build (standalone) --- +FROM node:22.14.0-slim AS builder +WORKDIR /app +RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \ + && rm -rf /var/lib/apt/lists/* +COPY --from=deps /app/node_modules ./node_modules +COPY . . +# Platzhalter nur für die Build-Zeit: prisma.config.ts löst env("DATABASE_URL") +# beim Laden auf, und Coolify reicht die Variable nur als Build-ARG rein (nicht in +# process.env). 'prisma generate' und 'next build' (nur dynamische Routen) bauen KEINE +# echte DB-Verbindung auf. Zur Laufzeit überschreibt der echte DATABASE_URL aus der +# Coolify-Env diesen Wert (im migrate-/app-Container). +ENV DATABASE_URL="postgresql://build:build@localhost:5432/build?schema=public" +RUN npx prisma generate && npm run build + +# --- Migrate-Stage: schlanker Job-Container für `prisma migrate deploy` (+ optional Seed/Bootstrap) --- +# Bewusst OHNE `next build`: enthält damit weder den kompilierten Next-Server (.next/standalone) +# noch den Build-Cache — deutlich kleinere Angriffsfläche als die builder-Stage (bisher genutzt). +# Warum nicht "nur Prisma-CLI"? prisma/seed.ts und scripts/bootstrap-admin.ts importieren aus +# ../src bzw. @/server (provisionTenant, rbac, modules) und laufen über tsx. Ein reiner +# Prisma-CLI-Container würde diese Jobs brechen. Da src/** in dieser Lane nicht angefasst werden +# darf, bleiben devDeps (tsx/prisma) + src hier nötig — eine spätere Entkopplung von Seed/Bootstrap +# vom App-Code ist als Folgeänderung empfohlen. +FROM node:22.14.0-slim AS migrate +WORKDIR /app +ENV NODE_ENV=production +RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \ + && rm -rf /var/lib/apt/lists/* +COPY --from=deps /app/node_modules ./node_modules +COPY package.json package-lock.json prisma.config.ts tsconfig.json ./ +COPY prisma ./prisma +COPY scripts ./scripts +COPY src ./src +# seed/ trägt das Richtlinien-Vorlagenpaket (mapping.json + Quelldateien), das der +# Demo-Seed (prisma/seed.ts) bzw. Bootstrap über importPolicies liest. Ohne diesen COPY +# bricht der migrate-Job mit ENOENT auf seed/isms-vorlagenpaket-v2/mapping.json ab. +# Einige Quelldateien liegen als 0600 vor → a+rX, damit der non-root app-User sie lesen kann. +COPY seed ./seed +RUN chmod -R a+rX ./seed +# docs/wizard-uebergabe/: Fachcontent-Quelldateien, aus denen der Demo-Seed den +# Risikokatalog (C4, import-risks.ts) und die Umsetzungshinweise (C6, import-hints.ts) +# liest. Nur im migrate-Image nötig — die Laufzeit/runner ruft diese Importer nicht auf +# (importManaged in provision.ts liest keine Dateien). Ohne diesen COPY bricht der +# Demo-Seed mit ENOENT auf docs/wizard-uebergabe/.../C6_Umsetzungshinweise.md ab. +COPY docs/wizard-uebergabe ./docs/wizard-uebergabe +RUN chmod -R a+rX ./docs +# Prisma-Client für Seed/Bootstrap generieren (migrate deploy selbst braucht nur schema+migrations). +ENV DATABASE_URL="postgresql://build:build@localhost:5432/build?schema=public" +RUN npx prisma generate +RUN groupadd --system --gid 1001 app \ + && useradd --system --uid 1001 --gid app --home-dir /app app +USER app +# Default-Kommando; im Compose (migrate-Service) überschrieben/erweitert. +CMD ["npx", "prisma", "migrate", "deploy"] + +# --- Runner-Stage: schlanker Produktions-Container (nur Next-Standalone) --- +FROM node:22.14.0-slim AS runner +WORKDIR /app +ENV NODE_ENV=production +# Next.js standalone server.js bindet sonst an den von Docker gesetzten HOSTNAME +# (= Container-ID) statt an alle Interfaces -> Healthcheck (127.0.0.1) und der +# Coolify-/Traefik-Proxy erreichen den Container nicht (404). 0.0.0.0 behebt beides. +ENV HOSTNAME=0.0.0.0 +ENV PORT=3000 +# Non-root-Nutzer (Debian: groupadd/useradd statt Alpine adduser -S). +RUN groupadd --system --gid 1001 app \ + && useradd --system --uid 1001 --gid app --home-dir /app app +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static +COPY --from=builder /app/public ./public +# Richtlinien-Vorlagenpaket für den Laufzeit-Import: Modul „policies" aktivieren +# (toggleTenantModule), Mandant mit Seed anlegen (createTenant), manueller Paket-Import +# (importPolicyPackageForTenant) lesen alle aus seed/isms-vorlagenpaket-v2/. Fehlt es, +# wirft die App zur Laufzeit ENOENT. a+rX wegen der 0600-Quelldateien (non-root app-User). +COPY seed ./seed +RUN chmod -R a+rX ./seed +# Backup-/Restore-/DSGVO-Topologie (src/server/backup/topology.ts) liest zur Laufzeit +# prisma/schema.prisma: Prisma 7 entfernt relationFromFields aus dem Laufzeit-DMMF, +# die FK-Relationen kommen daher aus der Schema-Datei. Der Inline-Export (Direkt- +# Download /api/platform/backup/download) läuft in der APP → ohne diese Datei ENOENT. +COPY prisma/schema.prisma ./prisma/schema.prisma +RUN chmod a+rX ./prisma/schema.prisma +USER app +EXPOSE 3000 +CMD ["node", "server.js"] + +# --- Garage-Stage: Objektspeicher-Image mit EINGEBACKENER Config --- +# Warum nicht das Upstream-Image + Bind-Mount der deploy/garage.toml? Coolify behandelt +# relative Bind-Mount-Quellen als Storage und legt sie als VERZEICHNIS an, wenn die Datei +# dort (noch) nicht existiert. Garage bekommt dann /etc/garage.toml als Ordner und bricht +# mit „IO error: Is a directory (os error 21)" ab. Das Backen der Config ins Image umgeht +# jeden Host-Mount. Secrets bleiben draußen (rpc_secret/admin_token kommen zur Laufzeit aus +# GARAGE_RPC_SECRET/GARAGE_ADMIN_TOKEN); nur die secret-freie Basiskonfig wird kopiert. +FROM dxflrs/garage:v1.2.0 AS garage +COPY deploy/garage.toml /etc/garage.toml diff --git a/README.md b/README.md new file mode 100644 index 0000000..95cb9b4 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# ISMS-Tool + +Multi-Tenant-SaaS zum Betrieb eines Informationssicherheits-Managementsystems (ISMS), ausgerichtet auf **ISO/IEC 27001:2022** und **TISAX / VDA-ISA 6.0**. + +📄 Vollständige Spezifikation: [docs/SPEC.md](docs/SPEC.md) · UI-Mockup: [docs/ISMS-Prototyp-GEFIM.html](docs/ISMS-Prototyp-GEFIM.html) + +## Module + +- **Assets & BIA** — Asset-Inventar und Business Impact Analyse als gemeinsames Modul (Schutzbedarf, RTO/RPO/MTD, primäre/sekundäre Assets, zugeordnete Risiken) +- **Risikoanalyse** — 5×5-Heatmap mit Drag-and-Drop, Detailansicht mit Maßnahmen, betroffenen Assets und Rest-Risiko +- **SoA & Control-Kataloge** — ISO 27001:2022 Annex A (93 Controls), VDA-ISA-6.0-Struktur mit Reifegraden +- **Maßnahmen** — Kanban, wiederkehrende Aufgaben, Fristen und Eskalation +- **Vorfälle, Audits, Lieferanten, Nachweise, Richtlinien (KI-Assistent), RAG-Chat, Dashboards, Management-Review** + +## Tech-Stack + +Next.js (App Router, TypeScript) · Prisma + PostgreSQL 16 (pgvector) · BullMQ + Redis · MinIO (S3) · Auth.js · Tailwind CSS + shadcn/ui · Docker Compose + +## Quickstart (Entwicklung) + +```bash +cp .env.example .env # Werte anpassen +docker compose up -d postgres redis minio # Infrastruktur starten +npm install +npx prisma migrate dev # Datenbank migrieren +npm run dev # http://localhost:3000 +``` + +Produktions-Stack (App + Worker + Infrastruktur): + +```bash +docker compose up -d --build +``` + +## Projektstruktur + +``` +docs/ Spezifikation (SPEC.md) und UI-Mockup +prisma/ Datenbankschema, Migrationen, Seeds +src/app/ Next.js App Router (UI + API) +src/server/ Server-Logik (Tenant-Guard, RBAC, Services) +``` diff --git a/components.json b/components.json new file mode 100644 index 0000000..8d886db --- /dev/null +++ b/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "base-nova", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/deploy/garage.toml b/deploy/garage.toml new file mode 100644 index 0000000..e82e47d --- /dev/null +++ b/deploy/garage.toml @@ -0,0 +1,34 @@ +# Garage-Objektspeicher — Basiskonfiguration (Single-Node pro Environment). +# Gehört zur MinIO→Garage-Migration, siehe docs/KONZEPT-garage-migration.md (§5). +# +# WICHTIG — KEINE Secrets in dieser Datei (sie ist im Repo eingecheckt): +# rpc_secret ← wird zur Laufzeit aus GARAGE_RPC_SECRET gelesen +# admin_token ← wird zur Laufzeit aus GARAGE_ADMIN_TOKEN gelesen +# Der Garage-Daemon übernimmt beide Werte aus der Umgebung (Coolify-Env). Beide +# NICHT über ${…} referenzieren, sondern literal in Coolify setzen (Interpolationsfalle). + +metadata_dir = "/var/lib/garage/meta" +data_dir = "/var/lib/garage/data" + +# LMDB-Metadaten-Engine (Default, robust für Single-Node). +db_engine = "lmdb" + +# Single-Node: eine Kopie (D5). Multi-Node/Replikation ist eine spätere Ausbaustufe. +replication_factor = 1 + +# RPC nur clusterintern. rpc_public_addr = loopback genügt für den Single-Node: +# das Provisioning spricht die Admin-API (HTTP 3903), nicht den RPC-Port — es braucht +# daher keine dienstübergreifende RPC-Adresse. Hält zugleich den `garage status`- +# Healthcheck (verbindet auf rpc_public_addr) unabhängig von Compose-DNS. +rpc_bind_addr = "[::]:3901" +rpc_public_addr = "127.0.0.1:3901" + +[s3_api] +# Region beidseitig us-east-1 (D2) — deckt sich mit dem App-Default (S3_REGION). +s3_region = "us-east-1" +api_bind_addr = "[::]:3900" + +[admin] +# Admin-API (Bucket-/Key-/Layout-Verwaltung, /health). Nur clusterintern, admin_token +# aus der Env. 3902 (Web) wird nicht benötigt und bewusst nicht gebunden. +api_bind_addr = "[::]:3903" diff --git a/docker-compose.coolify.prebuilt.yml b/docker-compose.coolify.prebuilt.yml new file mode 100644 index 0000000..f564f20 --- /dev/null +++ b/docker-compose.coolify.prebuilt.yml @@ -0,0 +1,460 @@ +# Coolify-Deployment (PREBUILT-Variante) — zieht fertige Images aus der Registry +# statt auf dem Host zu bauen (Plan B: langsamer/timeoutender Host-Build umgehen). +# Images vorher bauen+pushen: scripts/build-and-push-images.sh +# Registry/Tag via Coolify-Env: REGISTRY (Default git.certvia.de/msolarczek), IMAGE_TAG (Default main). +# Abgeleitet von docker-compose.coolify.yml. +# Unterschiede zum lokalen Dev-Compose: +# - keine host "ports": Coolify-Proxy routet die Domain intern auf app:3000 +# - Konfiguration über Coolify-Env-Variablen statt env_file: .env +# - Service "migrate": Init-Job (prisma migrate deploy + Rollen-Rechte-Sync), läuft einmalig VOR app +# - kein mailhog (Dev); Service "worker" = SEC1 Mail-Worker (BullMQ/Redis-Queue) +# In Coolify als "Docker Compose Location" -> docker-compose.coolify.yml setzen. +# +# Härtung (F-11/F-18): +# - F-11: migrate nutzt die schlanke "migrate"-Stage (kein Next-Build), Images gepinnt. +# - F-18: Backend-Dienste (postgres/redis/garage/migrate) im internen Netz ohne Egress; +# nur app zusätzlich im default-Netz (Coolify-Proxy). Redis mit Passwort. +# Überall no-new-privileges, cap_drop ALL (+gezielte cap_add), Ressourcenlimits. +services: + # Einmaliger Migrations-Job. Nutzt die schlanke "migrate"-Stage (Prisma-CLI/tsx + src, + # aber OHNE next build/.next) — kleinere Angriffsfläche als die frühere builder-Stage. + # Nach `migrate deploy` läuft der Rollen-Rechte-Sync (scripts/sync-role-permissions.ts): + # additiv + idempotent, zieht neu eingeführte Rechte für bestehende Mandanten nach + # (F-06 × F-10). Bei 0 Änderungen ein No-op. Betroffene Nutzer danach neu einloggen. + # Optionaler Demo-Seed nur, wenn RUN_DEMO_SEED=true (Testserver). Idempotent (upserts). + # In Produktion die Variable NICHT setzen; stattdessen BOOTSTRAP_ADMIN. + migrate: + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main} + command: sh -c "npx prisma migrate deploy && echo '>> Rollen-Rechte-Sync läuft…' && npx tsx scripts/sync-role-permissions.ts && echo '>> Vorlagen-Sync läuft…' && npx tsx scripts/sync-policy-templates.ts && if [ \"$$RUN_DEMO_SEED\" = \"true\" ]; then echo '>> Demo-Seed läuft…'; npx tsx prisma/seed.ts; fi && if [ \"$$BOOTSTRAP_ADMIN\" = \"true\" ]; then echo '>> Bootstrap-Admin läuft…'; npx tsx scripts/bootstrap-admin.ts; fi" + environment: + DATABASE_URL: ${DATABASE_URL} + # Härtung §1: Passwort-Pepper (Argon2 `secret`). Seed/Bootstrap hashen Passwörter + # → fail-secure, ohne gültigen 32-Byte-Hex wirft hashPassword und der Job scheitert. + # Muss identisch zum app-Service sein (sonst verifizieren die Hashes später nicht). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # Test: Demo-Seed. Produktiv: stattdessen BOOTSTRAP_ADMIN (Erst-Superadmin). + RUN_DEMO_SEED: ${RUN_DEMO_SEED:-false} + BOOTSTRAP_ADMIN: ${BOOTSTRAP_ADMIN:-false} + BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL:-} + BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-} + BOOTSTRAP_ADMIN_NAME: ${BOOTSTRAP_ADMIN_NAME:-} + BOOTSTRAP_TENANT_NAME: ${BOOTSTRAP_TENANT_NAME:-} + BOOTSTRAP_TENANT_SLUG: ${BOOTSTRAP_TENANT_SLUG:-} + BOOTSTRAP_TENANT_SHORT: ${BOOTSTRAP_TENANT_SHORT:-} + BOOTSTRAP_TENANT_SECTOR: ${BOOTSTRAP_TENANT_SECTOR:-} + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + depends_on: + postgres: + condition: service_healthy + restart: "no" + + app: + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-app:${IMAGE_TAG:-main} + environment: + DATABASE_URL: ${DATABASE_URL} + # F-04: Row Level Security scharf. Der migrate-Job oben läuft bewusst + # weiter mit der Owner-DATABASE_URL (BYPASSRLS). Nur der App-Prozess + # verbindet als eingeschränkte Rolle isms_app (NOBYPASSRLS) über + # RLS_DATABASE_URL und setzt app.tenant_id pro Transaktion. + RLS_ENFORCED: ${RLS_ENFORCED:-false} + RLS_DATABASE_URL: ${RLS_DATABASE_URL} + # F-18: REDIS_URL wird AUS REDIS_PASSWORD abgeleitet (nicht separat setzen!) — so + # bleibt sie immer konsistent zum `--requirepass` des redis-Dienstes und Coolify + # kann sie nicht als „managed" sperren. In Coolify NUR REDIS_PASSWORD setzen. + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 + AUTH_SECRET: ${AUTH_SECRET} + # Härtung §1: Passwort-Pepper (Argon2 `secret`). Fail-secure — ohne gültigen + # 32-Byte-Hex wirft jeder Login/hash. Muss IDENTISCH zum migrate-Job sein und + # ⚠ nach dem Setzen nicht mehr ändern (sonst verifizieren bestehende Hashes nicht). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # SEC3-d: TOTP-Secrets werden „at rest" mit AES-256-GCM verschlüsselt + # (src/server/secret-crypto.ts). Der Schlüssel leitet sich aus MFA_ENC_KEY + # ab, sonst aus AUTH_SECRET — daher OPTIONAL (leer = Fallback AUTH_SECRET). + # ⚠ Nach dem Setzen nicht mehr ändern: macht bereits verschlüsselte + # TOTP-Secrets unlesbar (kein Umschlüssel-Tool). + MFA_ENC_KEY: ${MFA_ENC_KEY:-} + AUTH_URL: ${AUTH_URL} + # Hinter dem Coolify/Traefik-Proxy zwingend für Auth.js v5 (sonst UntrustedHost). + AUTH_TRUST_HOST: ${AUTH_TRUST_HOST:-true} + S3_ENDPOINT: ${S3_ENDPOINT} + S3_ACCESS_KEY: ${S3_ACCESS_KEY} + S3_SECRET_KEY: ${S3_SECRET_KEY} + S3_BUCKET: ${S3_BUCKET} + # S1: echter S3-Adapter (src/server/storage/adapter.ts). Region ist für MinIO + # beliebig (Default us-east-1); überschreibbar für echtes AWS-S3. + S3_REGION: ${S3_REGION:-us-east-1} + # Lokaler (persistenter) Backup-Zielspeicher, wenn der Betreiber im Portal „Lokal" + # wählt bzw. als Env-Fallback. Muss auf das gemountete `backups`-Volume zeigen, + # sonst sind Sicherungen beim Redeploy flüchtig. DB-Config hat Vorrang vor dieser Var. + BACKUP_LOCAL_DIR: ${BACKUP_LOCAL_DIR:-/app/.backups} + AI_PROVIDER: ${AI_PROVIDER} + AI_API_KEY: ${AI_API_KEY} + SMTP_HOST: ${SMTP_HOST} + SMTP_PORT: ${SMTP_PORT} + SMTP_USER: ${SMTP_USER} + SMTP_PASSWORD: ${SMTP_PASSWORD} + SMTP_FROM: ${SMTP_FROM} + # Persistenter lokaler Backup-Zielspeicher (überlebt Redeploys). + volumes: + - backups:/app/.backups + # app im internen Netz (Backend-Zugriff) UND im default-Netz (Coolify-Proxy-Routing). + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + garage: + condition: service_healthy + garage-provision: + condition: service_completed_successfully + migrate: + condition: service_completed_successfully + healthcheck: + # Dependency-frei (node ist im Image vorhanden); alles < 500 gilt als gesund + test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:3000/',r=>process.exit(r.statusCode<500?0:1)).on('error',()=>process.exit(1))"] + interval: 15s + timeout: 5s + retries: 10 + start_period: 30s + restart: unless-stopped + + # SEC1: Mail-Worker. Eigener Langläufer-Prozess, der die BullMQ/Redis-Queue + # abarbeitet (Zustellung mit Retry/DLQ + täglicher Fristen-/Reminder-Job). + # Ist REDIS_URL gesetzt, reiht die App Jobs ein und DIESER Worker stellt zu; + # ohne REDIS_URL versendet die App inline und der Worker wird nicht gebraucht. + # Nutzt das schlanke "migrate"-Image (tsx + src + Mail-Deps + Prisma-Client). + # Owner-DATABASE_URL (kein RLS): der Worker arbeitet mandantenübergreifend. + # Im default-Netz (Egress), damit der externe SMTP-Server erreichbar ist. + worker: + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main} + command: ["npx", "tsx", "scripts/mail-worker.ts"] + environment: + DATABASE_URL: ${DATABASE_URL} + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 + # SMTP: fehlt die Konfiguration, bleibt der Worker aktiv und meldet den + # Zustand (Jobs bleiben pending) — kein Neustart-Rennen beim Nachreichen. + SMTP_HOST: ${SMTP_HOST} + SMTP_PORT: ${SMTP_PORT} + SMTP_SECURE: ${SMTP_SECURE:-} + SMTP_USER: ${SMTP_USER} + SMTP_PASSWORD: ${SMTP_PASSWORD} + SMTP_FROM: ${SMTP_FROM} + # Absolute Links in Mails (Reset etc.): APP_BASE_URL, sonst AUTH_URL. + AUTH_URL: ${AUTH_URL} + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + migrate: + condition: service_completed_successfully + restart: unless-stopped + + # Backup-Worker: arbeitet die BullMQ-Queue "backup-ops" ab (Portal-Restore, + # "Export jetzt", DSGVO-Zustellung). OHNE diesen Dienst bleiben angestoßene Jobs + # dauerhaft auf "queued" (die App reiht nur ein, führt NICHT inline aus). + # Owner-DATABASE_URL (kein RLS): Restore/Export laufen mandantenübergreifend und + # brauchen einen Superuser-Owner (session_replication_role beim Restore). + # Braucht das S3/MinIO-Backup-Bucket (S3_*) und den Backup-Schlüssel (BACKUP_ENC_KEY, + # Fallback AUTH_SECRET). concurrency ist im Worker seriell (destruktiv). + backup-worker: + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main} + command: ["npx", "tsx", "scripts/backup-worker.ts"] + environment: + DATABASE_URL: ${DATABASE_URL} + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 + AUTH_SECRET: ${AUTH_SECRET} + # Pepper wird von der Fail-Secure-Startprüfung erwartet (assertSecureEnv). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # Backup-Artefakt-Verschlüsselung (AES-256-GCM); ohne eigenen Key = AUTH_SECRET. + BACKUP_ENC_KEY: ${BACKUP_ENC_KEY:-} + # Objektspeicher für Backup-Artefakte + DSGVO-Pakete (S3/MinIO). Fehlt es, + # nutzt der Store einen lokalen (ephemeren!) Ordner — für Prod S3_* setzen. + S3_ENDPOINT: ${S3_ENDPOINT:-} + S3_ACCESS_KEY: ${S3_ACCESS_KEY:-} + S3_SECRET_KEY: ${S3_SECRET_KEY:-} + S3_BUCKET: ${S3_BUCKET:-} + S3_REGION: ${S3_REGION:-} + # Lokaler (persistenter) Backup-Zielspeicher — identischer Mount wie beim app-Service, + # damit „Lokal" für Worker (schreibt Artefakte) und app (liest im Portal) dasselbe + # Volume sieht. DB-Config aus dem Betreiber-Portal hat Vorrang vor dieser Var. + BACKUP_LOCAL_DIR: ${BACKUP_LOCAL_DIR:-/app/.backups} + AUTH_URL: ${AUTH_URL} + # Gleiches persistentes Volume wie app (gemeinsamer lokaler Zielspeicher). + volumes: + - backups:/app/.backups + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + migrate: + condition: service_completed_successfully + restart: unless-stopped + + # IM-D — Inbound-Mail-Worker (E-Mail-to-Ticket). Holt Mails vom Catch-all-Postfach + # (vorfall-@in.certvia.de) per IMAP ab und legt daraus Vorfälle an bzw. reiht + # unklare Mails in die Betreiber-Review. Kein Redis nötig (IMAP-Poller, keine Queue). + # Ohne INCIDENT_IMAP_* beendet sich der Prozess sauber („nicht konfiguriert"). + incident-inbound-worker: + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main} + command: ["npx", "tsx", "scripts/incident-inbound-worker.ts"] + environment: + DATABASE_URL: ${DATABASE_URL} + AUTH_SECRET: ${AUTH_SECRET} + # Pepper wird von der Fail-Secure-Startprüfung erwartet (assertSecureEnv). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # IMAP-Zugang des Catch-all-Postfachs. Fehlt es, beendet sich der Worker sauber. + INCIDENT_IMAP_HOST: ${INCIDENT_IMAP_HOST:-} + INCIDENT_IMAP_PORT: ${INCIDENT_IMAP_PORT:-993} + INCIDENT_IMAP_USER: ${INCIDENT_IMAP_USER:-} + INCIDENT_IMAP_PASSWORD: ${INCIDENT_IMAP_PASSWORD:-} + INCIDENT_IMAP_TLS: ${INCIDENT_IMAP_TLS:-true} + INCIDENT_IMAP_MAILBOX: ${INCIDENT_IMAP_MAILBOX:-INBOX} + INCIDENT_IMAP_POLL_MS: ${INCIDENT_IMAP_POLL_MS:-60000} + # Muss zur Catch-all-Subdomain passen (Ableitung der Intake-Adressen). + INCIDENT_INTAKE_DOMAIN: ${INCIDENT_INTAKE_DOMAIN:-in.certvia.de} + AUTH_URL: ${AUTH_URL} + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + depends_on: + postgres: + condition: service_healthy + migrate: + condition: service_completed_successfully + restart: unless-stopped + + postgres: + image: pgvector/pgvector:0.8.0-pg16 + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - pgdata:/var/lib/postgresql/data + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + # Postgres-Entrypoint chownt das Datadir und wechselt per gosu auf den postgres-User. + cap_add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 5s + timeout: 5s + retries: 10 + restart: unless-stopped + + redis: + image: redis:7.4.2-alpine + # F-18: Redis mit Passwort. REDIS_URL (app) muss dieses Passwort tragen. + command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"] + volumes: + - redisdata:/data + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + # redis-alpine-Entrypoint chownt /data und wechselt per gosu auf den redis-User. + cap_add: + - CHOWN + - SETGID + - SETUID + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + restart: unless-stopped + + # Objektspeicher: Garage (S3-kompatibel) — ersetzt den früheren minio-Service + # (MinIO Community EOL/Maintenance-Mode). Konzept: docs/KONZEPT-garage-migration.md. + # Buckets/Keys werden NICHT über die S3-API angelegt, sondern vom Init-Job + # "garage-provision" (Admin-API). Nichts nach außen (kein Traefik/ports:) — + # rein clusterintern, wie minio zuvor. Version gepinnt (kein latest). + garage: + # Image mit eingebackener deploy/garage.toml (Dockerfile-Stage „garage"). KEIN + # Bind-Mount der Config: Coolify legt relative Bind-Quellen sonst als Verzeichnis an + # → Garage bekäme /etc/garage.toml als Ordner („IO error: Is a directory"). + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-garage:${IMAGE_TAG:-main} + # Secrets stehen NICHT in der eingebackenen deploy/garage.toml — der Daemon liest + # rpc_secret/admin_token aus der Env (in Coolify literal setzen, nicht via ${…}). + environment: + GARAGE_RPC_SECRET: ${GARAGE_RPC_SECRET} + GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN} + volumes: + # KRITISCH: meta enthält Bucket-/Key-/Layout-Definitionen → MUSS ins Host-Backup + # (analog pgdata). Ohne meta sind die Objektdaten nicht adressierbar. + - garage_meta:/var/lib/garage/meta + - garage_data:/var/lib/garage/data + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + healthcheck: + # Distroless-Image (nur /garage): der CLI-Status dient als Health-Signal. + # Verbindet auf rpc_public_addr (loopback) → unabhängig von Compose-DNS. + test: ["CMD", "/garage", "status"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 10s + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + restart: unless-stopped + + # Idempotenter Provisioning-Job (analog "migrate", restart:no): stellt aus einer + # leeren Garage Layout + Bucket + Access-Key + Rechte her (Garage-Admin-API, HTTP). + # Läuft bei JEDEM Deploy; "already exists" = Erfolg. Ohne GARAGE_ADMIN_TOKEN No-op. + # Nutzt das schlanke "migrate"-Image (Node/tsx) — kein Garage-Binary nötig. + garage-provision: + image: ${REGISTRY:-git.certvia.de/msolarczek}/certvia-migrate:${IMAGE_TAG:-main} + command: ["npx", "tsx", "scripts/garage-provision.ts"] + environment: + GARAGE_ADMIN_URL: http://garage:3903 + GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN} + # Der zu importierende Garage-Key = App-Key (App-Env und Garage synchron). + S3_ACCESS_KEY: ${S3_ACCESS_KEY} + S3_SECRET_KEY: ${S3_SECRET_KEY} + S3_BUCKET: ${S3_BUCKET:-isms-documents} + # Optionaler separater Backup-Bucket (nur falls Backup-Store auf S3 statt lokal). + BACKUP_S3_BUCKET: ${BACKUP_S3_BUCKET:-} + # Single-Node-Layout (nominale Kapazität/Zone; für Prod ggf. anheben). + GARAGE_ZONE: ${GARAGE_ZONE:-dc1} + GARAGE_CAPACITY_BYTES: ${GARAGE_CAPACITY_BYTES:-100000000000} + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + depends_on: + garage: + condition: service_healthy + restart: "no" + + # ── ROLLBACK-NETZ (bis Garage abgenommen ist; danach entfernen) ─────────────── + # Der alte minio-Service bleibt vorübergehend auskommentiert stehen, damit ein + # Rollback ohne Repo-Archäologie möglich ist. NACH erfolgreicher Garage-Abnahme + # diesen Block UND das Volume "miniodata" (unten) entfernen. + # minio: + # image: minio/minio:RELEASE.2025-04-22T22-12-26Z + # command: server /data --console-address ":9001" + # environment: + # MINIO_ROOT_USER: ${MINIO_ROOT_USER} + # MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} + # volumes: + # - miniodata:/data + # networks: + # - backend + # security_opt: + # - "no-new-privileges:true" + # cap_drop: + # - ALL + # deploy: + # resources: + # limits: + # cpus: "0.5" + # memory: 512M + # restart: unless-stopped + +networks: + # Internes Netz ohne Egress/Host-Exposure für die Backend-Dienste. + backend: + internal: true + # default: von Coolify für das Proxy-Routing zur app genutzt (mit Egress). + default: + +volumes: + pgdata: + redisdata: + # Garage-Objektspeicher. garage_meta ist KRITISCH (Bucket-/Key-/Layout-Definitionen) + # und MUSS in die Host-Backup-Strategie (analog pgdata) — ohne meta sind die Daten + # in garage_data nicht adressierbar. + garage_meta: + garage_data: + # ROLLBACK: altes MinIO-Datenvolume. Nach abgenommener Garage-Migration entfernen. + miniodata: + # Persistenter lokaler Backup-Zielspeicher (Lane „Konfigurierbarer Backup-Zielspeicher"). + # Von app + backup-worker unter /app/.backups gemountet, damit „Lokal" Redeploys überlebt. + backups: diff --git a/docker-compose.coolify.yml b/docker-compose.coolify.yml new file mode 100644 index 0000000..b5614e0 --- /dev/null +++ b/docker-compose.coolify.yml @@ -0,0 +1,470 @@ +# Coolify-Deployment (Testserver/Prod, intern) — abgeleitet von docker-compose.yml. +# Unterschiede zum lokalen Dev-Compose: +# - keine host "ports": Coolify-Proxy routet die Domain intern auf app:3000 +# - Konfiguration über Coolify-Env-Variablen statt env_file: .env +# - Service "migrate": Init-Job (prisma migrate deploy + Rollen-Rechte-Sync), läuft einmalig VOR app +# - kein mailhog (Dev); Service "worker" = SEC1 Mail-Worker (BullMQ/Redis-Queue) +# In Coolify als "Docker Compose Location" -> docker-compose.coolify.yml setzen. +# +# Härtung (F-11/F-18): +# - F-11: migrate nutzt die schlanke "migrate"-Stage (kein Next-Build), Images gepinnt. +# - F-18: Backend-Dienste (postgres/redis/garage/migrate) im internen Netz ohne Egress; +# nur app zusätzlich im default-Netz (Coolify-Proxy). Redis mit Passwort. +# Überall no-new-privileges, cap_drop ALL (+gezielte cap_add), Ressourcenlimits. +services: + # Einmaliger Migrations-Job. Nutzt die schlanke "migrate"-Stage (Prisma-CLI/tsx + src, + # aber OHNE next build/.next) — kleinere Angriffsfläche als die frühere builder-Stage. + # Nach `migrate deploy` läuft der Rollen-Rechte-Sync (scripts/sync-role-permissions.ts): + # additiv + idempotent, zieht neu eingeführte Rechte für bestehende Mandanten nach + # (F-06 × F-10). Bei 0 Änderungen ein No-op. Betroffene Nutzer danach neu einloggen. + # Optionaler Demo-Seed nur, wenn RUN_DEMO_SEED=true (Testserver). Idempotent (upserts). + # In Produktion die Variable NICHT setzen; stattdessen BOOTSTRAP_ADMIN. + migrate: + build: + context: . + target: migrate + command: sh -c "npx prisma migrate deploy && echo '>> Rollen-Rechte-Sync läuft…' && npx tsx scripts/sync-role-permissions.ts && echo '>> Vorlagen-Sync läuft…' && npx tsx scripts/sync-policy-templates.ts && if [ \"$$RUN_DEMO_SEED\" = \"true\" ]; then echo '>> Demo-Seed läuft…'; npx tsx prisma/seed.ts; fi && if [ \"$$BOOTSTRAP_ADMIN\" = \"true\" ]; then echo '>> Bootstrap-Admin läuft…'; npx tsx scripts/bootstrap-admin.ts; fi" + environment: + DATABASE_URL: ${DATABASE_URL} + # Härtung §1: Passwort-Pepper (Argon2 `secret`). Seed/Bootstrap hashen Passwörter + # → fail-secure, ohne gültigen 32-Byte-Hex wirft hashPassword und der Job scheitert. + # Muss identisch zum app-Service sein (sonst verifizieren die Hashes später nicht). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # Test: Demo-Seed. Produktiv: stattdessen BOOTSTRAP_ADMIN (Erst-Superadmin). + RUN_DEMO_SEED: ${RUN_DEMO_SEED:-false} + BOOTSTRAP_ADMIN: ${BOOTSTRAP_ADMIN:-false} + BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL:-} + BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-} + BOOTSTRAP_ADMIN_NAME: ${BOOTSTRAP_ADMIN_NAME:-} + BOOTSTRAP_TENANT_NAME: ${BOOTSTRAP_TENANT_NAME:-} + BOOTSTRAP_TENANT_SLUG: ${BOOTSTRAP_TENANT_SLUG:-} + BOOTSTRAP_TENANT_SHORT: ${BOOTSTRAP_TENANT_SHORT:-} + BOOTSTRAP_TENANT_SECTOR: ${BOOTSTRAP_TENANT_SECTOR:-} + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + depends_on: + postgres: + condition: service_healthy + restart: "no" + + app: + build: + context: . + target: runner + environment: + DATABASE_URL: ${DATABASE_URL} + # F-04: Row Level Security scharf. Der migrate-Job oben läuft bewusst + # weiter mit der Owner-DATABASE_URL (BYPASSRLS). Nur der App-Prozess + # verbindet als eingeschränkte Rolle isms_app (NOBYPASSRLS) über + # RLS_DATABASE_URL und setzt app.tenant_id pro Transaktion. + RLS_ENFORCED: ${RLS_ENFORCED:-false} + RLS_DATABASE_URL: ${RLS_DATABASE_URL} + # F-18: REDIS_URL wird AUS REDIS_PASSWORD abgeleitet (nicht separat setzen!) — so + # bleibt sie immer konsistent zum `--requirepass` des redis-Dienstes und Coolify + # kann sie nicht als „managed" sperren. In Coolify NUR REDIS_PASSWORD setzen. + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 + AUTH_SECRET: ${AUTH_SECRET} + # Härtung §1: Passwort-Pepper (Argon2 `secret`). Fail-secure — ohne gültigen + # 32-Byte-Hex wirft jeder Login/hash. Muss IDENTISCH zum migrate-Job sein und + # ⚠ nach dem Setzen nicht mehr ändern (sonst verifizieren bestehende Hashes nicht). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # SEC3-d: TOTP-Secrets werden „at rest" mit AES-256-GCM verschlüsselt + # (src/server/secret-crypto.ts). Der Schlüssel leitet sich aus MFA_ENC_KEY + # ab, sonst aus AUTH_SECRET — daher OPTIONAL (leer = Fallback AUTH_SECRET). + # ⚠ Nach dem Setzen nicht mehr ändern: macht bereits verschlüsselte + # TOTP-Secrets unlesbar (kein Umschlüssel-Tool). + MFA_ENC_KEY: ${MFA_ENC_KEY:-} + AUTH_URL: ${AUTH_URL} + # Hinter dem Coolify/Traefik-Proxy zwingend für Auth.js v5 (sonst UntrustedHost). + AUTH_TRUST_HOST: ${AUTH_TRUST_HOST:-true} + S3_ENDPOINT: ${S3_ENDPOINT} + S3_ACCESS_KEY: ${S3_ACCESS_KEY} + S3_SECRET_KEY: ${S3_SECRET_KEY} + S3_BUCKET: ${S3_BUCKET} + # S1: echter S3-Adapter (src/server/storage/adapter.ts). Region ist für MinIO + # beliebig (Default us-east-1); überschreibbar für echtes AWS-S3. + S3_REGION: ${S3_REGION:-us-east-1} + # Lokaler (persistenter) Backup-Zielspeicher, wenn der Betreiber im Portal „Lokal" + # wählt bzw. als Env-Fallback. Muss auf das gemountete `backups`-Volume zeigen, + # sonst sind Sicherungen beim Redeploy flüchtig. DB-Config hat Vorrang vor dieser Var. + BACKUP_LOCAL_DIR: ${BACKUP_LOCAL_DIR:-/app/.backups} + AI_PROVIDER: ${AI_PROVIDER} + AI_API_KEY: ${AI_API_KEY} + SMTP_HOST: ${SMTP_HOST} + SMTP_PORT: ${SMTP_PORT} + SMTP_USER: ${SMTP_USER} + SMTP_PASSWORD: ${SMTP_PASSWORD} + SMTP_FROM: ${SMTP_FROM} + # Persistenter lokaler Backup-Zielspeicher (überlebt Redeploys). + volumes: + - backups:/app/.backups + # app im internen Netz (Backend-Zugriff) UND im default-Netz (Coolify-Proxy-Routing). + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + garage: + condition: service_healthy + garage-provision: + condition: service_completed_successfully + migrate: + condition: service_completed_successfully + healthcheck: + # Dependency-frei (node ist im Image vorhanden); alles < 500 gilt als gesund + test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:3000/',r=>process.exit(r.statusCode<500?0:1)).on('error',()=>process.exit(1))"] + interval: 15s + timeout: 5s + retries: 10 + start_period: 30s + restart: unless-stopped + + # SEC1: Mail-Worker. Eigener Langläufer-Prozess, der die BullMQ/Redis-Queue + # abarbeitet (Zustellung mit Retry/DLQ + täglicher Fristen-/Reminder-Job). + # Ist REDIS_URL gesetzt, reiht die App Jobs ein und DIESER Worker stellt zu; + # ohne REDIS_URL versendet die App inline und der Worker wird nicht gebraucht. + # Nutzt das schlanke "migrate"-Image (tsx + src + Mail-Deps + Prisma-Client). + # Owner-DATABASE_URL (kein RLS): der Worker arbeitet mandantenübergreifend. + # Im default-Netz (Egress), damit der externe SMTP-Server erreichbar ist. + worker: + build: + context: . + target: migrate + command: ["npx", "tsx", "scripts/mail-worker.ts"] + environment: + DATABASE_URL: ${DATABASE_URL} + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 + # SMTP: fehlt die Konfiguration, bleibt der Worker aktiv und meldet den + # Zustand (Jobs bleiben pending) — kein Neustart-Rennen beim Nachreichen. + SMTP_HOST: ${SMTP_HOST} + SMTP_PORT: ${SMTP_PORT} + SMTP_SECURE: ${SMTP_SECURE:-} + SMTP_USER: ${SMTP_USER} + SMTP_PASSWORD: ${SMTP_PASSWORD} + SMTP_FROM: ${SMTP_FROM} + # Absolute Links in Mails (Reset etc.): APP_BASE_URL, sonst AUTH_URL. + AUTH_URL: ${AUTH_URL} + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + migrate: + condition: service_completed_successfully + restart: unless-stopped + + # Backup-Worker: arbeitet die BullMQ-Queue "backup-ops" ab (Portal-Restore, + # "Export jetzt", DSGVO-Zustellung). OHNE diesen Dienst bleiben angestoßene Jobs + # dauerhaft auf "queued" (die App reiht nur ein, führt NICHT inline aus). + # Owner-DATABASE_URL (kein RLS): Restore/Export laufen mandantenübergreifend und + # brauchen einen Superuser-Owner (session_replication_role beim Restore). + # Braucht das S3/MinIO-Backup-Bucket (S3_*) und den Backup-Schlüssel (BACKUP_ENC_KEY, + # Fallback AUTH_SECRET). concurrency ist im Worker seriell (destruktiv). + backup-worker: + build: + context: . + target: migrate + command: ["npx", "tsx", "scripts/backup-worker.ts"] + environment: + DATABASE_URL: ${DATABASE_URL} + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 + AUTH_SECRET: ${AUTH_SECRET} + # Pepper wird von der Fail-Secure-Startprüfung erwartet (assertSecureEnv). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # Backup-Artefakt-Verschlüsselung (AES-256-GCM); ohne eigenen Key = AUTH_SECRET. + BACKUP_ENC_KEY: ${BACKUP_ENC_KEY:-} + # Objektspeicher für Backup-Artefakte + DSGVO-Pakete (S3/MinIO). Fehlt es, + # nutzt der Store einen lokalen (ephemeren!) Ordner — für Prod S3_* setzen. + S3_ENDPOINT: ${S3_ENDPOINT:-} + S3_ACCESS_KEY: ${S3_ACCESS_KEY:-} + S3_SECRET_KEY: ${S3_SECRET_KEY:-} + S3_BUCKET: ${S3_BUCKET:-} + S3_REGION: ${S3_REGION:-} + # Lokaler (persistenter) Backup-Zielspeicher — identischer Mount wie beim app-Service, + # damit „Lokal" für Worker (schreibt Artefakte) und app (liest im Portal) dasselbe + # Volume sieht. DB-Config aus dem Betreiber-Portal hat Vorrang vor dieser Var. + BACKUP_LOCAL_DIR: ${BACKUP_LOCAL_DIR:-/app/.backups} + AUTH_URL: ${AUTH_URL} + # Gleiches persistentes Volume wie app (gemeinsamer lokaler Zielspeicher). + volumes: + - backups:/app/.backups + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + migrate: + condition: service_completed_successfully + restart: unless-stopped + + # IM-D — Inbound-Mail-Worker (E-Mail-to-Ticket). Holt Mails vom Catch-all-Postfach + # (vorfall-@in.certvia.de) per IMAP ab und legt daraus Vorfälle an bzw. reiht + # unklare Mails in die Betreiber-Review. Kein Redis nötig (IMAP-Poller, keine Queue). + # Ohne INCIDENT_IMAP_* beendet sich der Prozess sauber („nicht konfiguriert"). + incident-inbound-worker: + build: + context: . + target: migrate + command: ["npx", "tsx", "scripts/incident-inbound-worker.ts"] + environment: + DATABASE_URL: ${DATABASE_URL} + AUTH_SECRET: ${AUTH_SECRET} + # Pepper wird von der Fail-Secure-Startprüfung erwartet (assertSecureEnv). + PASSWORD_PEPPER: ${PASSWORD_PEPPER} + # IMAP-Zugang des Catch-all-Postfachs. Fehlt es, beendet sich der Worker sauber. + INCIDENT_IMAP_HOST: ${INCIDENT_IMAP_HOST:-} + INCIDENT_IMAP_PORT: ${INCIDENT_IMAP_PORT:-993} + INCIDENT_IMAP_USER: ${INCIDENT_IMAP_USER:-} + INCIDENT_IMAP_PASSWORD: ${INCIDENT_IMAP_PASSWORD:-} + INCIDENT_IMAP_TLS: ${INCIDENT_IMAP_TLS:-true} + INCIDENT_IMAP_MAILBOX: ${INCIDENT_IMAP_MAILBOX:-INBOX} + INCIDENT_IMAP_POLL_MS: ${INCIDENT_IMAP_POLL_MS:-60000} + # Muss zur Catch-all-Subdomain passen (Ableitung der Intake-Adressen). + INCIDENT_INTAKE_DOMAIN: ${INCIDENT_INTAKE_DOMAIN:-in.certvia.de} + AUTH_URL: ${AUTH_URL} + networks: + - backend + - default + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + depends_on: + postgres: + condition: service_healthy + migrate: + condition: service_completed_successfully + restart: unless-stopped + + postgres: + image: pgvector/pgvector:0.8.0-pg16 + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - pgdata:/var/lib/postgresql/data + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + # Postgres-Entrypoint chownt das Datadir und wechselt per gosu auf den postgres-User. + cap_add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 5s + timeout: 5s + retries: 10 + restart: unless-stopped + + redis: + image: redis:7.4.2-alpine + # F-18: Redis mit Passwort. REDIS_URL (app) muss dieses Passwort tragen. + command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"] + volumes: + - redisdata:/data + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + # redis-alpine-Entrypoint chownt /data und wechselt per gosu auf den redis-User. + cap_add: + - CHOWN + - SETGID + - SETUID + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + restart: unless-stopped + + # Objektspeicher: Garage (S3-kompatibel) — ersetzt den früheren minio-Service + # (MinIO Community EOL/Maintenance-Mode). Konzept: docs/KONZEPT-garage-migration.md. + # Buckets/Keys werden NICHT über die S3-API angelegt, sondern vom Init-Job + # "garage-provision" (Admin-API). Nichts nach außen (kein Traefik/ports:) — + # rein clusterintern, wie minio zuvor. Version gepinnt (kein latest). + garage: + # Image mit eingebackener deploy/garage.toml (Dockerfile-Stage „garage"). KEIN + # Bind-Mount der Config: Coolify legt relative Bind-Quellen sonst als Verzeichnis an + # → Garage bekäme /etc/garage.toml als Ordner („IO error: Is a directory"). + build: + context: . + target: garage + # Secrets stehen NICHT in der eingebackenen deploy/garage.toml — der Daemon liest + # rpc_secret/admin_token aus der Env (in Coolify literal setzen, nicht via ${…}). + environment: + GARAGE_RPC_SECRET: ${GARAGE_RPC_SECRET} + GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN} + volumes: + # KRITISCH: meta enthält Bucket-/Key-/Layout-Definitionen → MUSS ins Host-Backup + # (analog pgdata). Ohne meta sind die Objektdaten nicht adressierbar. + - garage_meta:/var/lib/garage/meta + - garage_data:/var/lib/garage/data + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + healthcheck: + # Distroless-Image (nur /garage): der CLI-Status dient als Health-Signal. + # Verbindet auf rpc_public_addr (loopback) → unabhängig von Compose-DNS. + test: ["CMD", "/garage", "status"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 10s + deploy: + resources: + limits: + cpus: "1.0" + memory: 1G + restart: unless-stopped + + # Idempotenter Provisioning-Job (analog "migrate", restart:no): stellt aus einer + # leeren Garage Layout + Bucket + Access-Key + Rechte her (Garage-Admin-API, HTTP). + # Läuft bei JEDEM Deploy; "already exists" = Erfolg. Ohne GARAGE_ADMIN_TOKEN No-op. + # Nutzt das schlanke "migrate"-Image (Node/tsx) — kein Garage-Binary nötig. + garage-provision: + build: + context: . + target: migrate + command: ["npx", "tsx", "scripts/garage-provision.ts"] + environment: + GARAGE_ADMIN_URL: http://garage:3903 + GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN} + # Der zu importierende Garage-Key = App-Key (App-Env und Garage synchron). + S3_ACCESS_KEY: ${S3_ACCESS_KEY} + S3_SECRET_KEY: ${S3_SECRET_KEY} + S3_BUCKET: ${S3_BUCKET:-isms-documents} + # Optionaler separater Backup-Bucket (nur falls Backup-Store auf S3 statt lokal). + BACKUP_S3_BUCKET: ${BACKUP_S3_BUCKET:-} + # Single-Node-Layout (nominale Kapazität/Zone; für Prod ggf. anheben). + GARAGE_ZONE: ${GARAGE_ZONE:-dc1} + GARAGE_CAPACITY_BYTES: ${GARAGE_CAPACITY_BYTES:-100000000000} + networks: + - backend + security_opt: + - "no-new-privileges:true" + cap_drop: + - ALL + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + depends_on: + garage: + condition: service_healthy + restart: "no" + + # ── ROLLBACK-NETZ (bis Garage abgenommen ist; danach entfernen) ─────────────── + # Der alte minio-Service bleibt vorübergehend auskommentiert stehen, damit ein + # Rollback ohne Repo-Archäologie möglich ist. NACH erfolgreicher Garage-Abnahme + # diesen Block UND das Volume "miniodata" (unten) entfernen. + # minio: + # image: minio/minio:RELEASE.2025-04-22T22-12-26Z + # command: server /data --console-address ":9001" + # environment: + # MINIO_ROOT_USER: ${MINIO_ROOT_USER} + # MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} + # volumes: + # - miniodata:/data + # networks: + # - backend + # security_opt: + # - "no-new-privileges:true" + # cap_drop: + # - ALL + # deploy: + # resources: + # limits: + # cpus: "0.5" + # memory: 512M + # restart: unless-stopped + +networks: + # Internes Netz ohne Egress/Host-Exposure für die Backend-Dienste. + backend: + internal: true + # default: von Coolify für das Proxy-Routing zur app genutzt (mit Egress). + default: + +volumes: + pgdata: + redisdata: + # Garage-Objektspeicher. garage_meta ist KRITISCH (Bucket-/Key-/Layout-Definitionen) + # und MUSS in die Host-Backup-Strategie (analog pgdata) — ohne meta sind die Daten + # in garage_data nicht adressierbar. + garage_meta: + garage_data: + # ROLLBACK: altes MinIO-Datenvolume. Nach abgenommener Garage-Migration entfernen. + miniodata: + # Persistenter lokaler Backup-Zielspeicher (Lane „Konfigurierbarer Backup-Zielspeicher"). + # Von app + backup-worker unter /app/.backups gemountet, damit „Lokal" Redeploys überlebt. + backups: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f2dcf5f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,127 @@ +# Lokales Dev-Compose. Härtung ggü. Backlog-Findings: +# - F-11: alle Images auf konkrete Tags gepinnt (kein :latest / rollender Tag) +# - F-18: Host-Ports NUR auf 127.0.0.1 gebunden (nicht auf allen Interfaces des +# Entwicklerrechners); Redis mit Passwort (requirepass); +# security_opt no-new-privileges auf allen Services. +# Für Prod/Testserver gilt docker-compose.coolify.yml (Netzsegmentierung, Limits etc.). +services: + app: + build: . + ports: + - "127.0.0.1:3000:3000" + env_file: .env + security_opt: + - "no-new-privileges:true" + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + garage: + condition: service_healthy + garage-provision: + condition: service_completed_successfully + restart: unless-stopped + + # Wird in Iteration 4 aktiviert (BullMQ-Scheduler, siehe docs/SPEC.md §4.5) + worker: + profiles: ["worker"] + build: . + command: ["npm", "run", "worker"] + env_file: .env + security_opt: + - "no-new-privileges:true" + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + restart: unless-stopped + + postgres: + image: pgvector/pgvector:0.8.0-pg16 + environment: + POSTGRES_USER: ${POSTGRES_USER:-isms} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-isms} + POSTGRES_DB: ${POSTGRES_DB:-isms} + volumes: + - pgdata:/var/lib/postgresql/data + ports: + - "127.0.0.1:5432:5432" + security_opt: + - "no-new-privileges:true" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-isms}"] + interval: 5s + timeout: 5s + retries: 10 + + redis: + image: redis:7.4.2-alpine + # F-18: Redis mit Passwort. REDIS_URL in .env muss das Passwort tragen, z. B. + # redis://:${REDIS_PASSWORD}@localhost:6379 + command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:-isms-redis}"] + volumes: + - redisdata:/data + ports: + - "127.0.0.1:6379:6379" + security_opt: + - "no-new-privileges:true" + + # Objektspeicher: Garage (S3-kompatibel) — ersetzt MinIO (EOL). S3-API auf 3900, + # Admin-API auf 3903 (nur lokal gebunden). Dev-Secrets kommen aus .env (siehe + # .env.example: GARAGE_RPC_SECRET/GARAGE_ADMIN_TOKEN, S3_ACCESS_KEY/S3_SECRET_KEY). + garage: + image: dxflrs/garage:v1.2.0 + environment: + GARAGE_RPC_SECRET: ${GARAGE_RPC_SECRET:-0000000000000000000000000000000000000000000000000000000000000002} + GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN:-0000000000000000000000000000000000000000000000000000000000000003} + volumes: + - ./deploy/garage.toml:/etc/garage.toml:ro + - garage_meta:/var/lib/garage/meta + - garage_data:/var/lib/garage/data + ports: + - "127.0.0.1:3900:3900" + - "127.0.0.1:3903:3903" + security_opt: + - "no-new-privileges:true" + healthcheck: + test: ["CMD", "/garage", "status"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 5s + + # Idempotenter Provisioning-Job (Layout + Bucket + Key + Rechte via Admin-API). + # Nutzt das App-Image (tsx vorhanden); läuft einmalig vor der app. + garage-provision: + build: . + command: ["npx", "tsx", "scripts/garage-provision.ts"] + environment: + GARAGE_ADMIN_URL: http://garage:3903 + GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN:-0000000000000000000000000000000000000000000000000000000000000003} + S3_ACCESS_KEY: ${S3_ACCESS_KEY:-GKdead0000beef0000cafe0000} + S3_SECRET_KEY: ${S3_SECRET_KEY:-0000000000000000000000000000000000000000000000000000000000000001} + S3_BUCKET: ${S3_BUCKET:-isms-documents} + GARAGE_CAPACITY_BYTES: ${GARAGE_CAPACITY_BYTES:-10000000000} + security_opt: + - "no-new-privileges:true" + depends_on: + garage: + condition: service_healthy + restart: "no" + + mailhog: + image: mailhog/mailhog:v1.0.1 + profiles: ["dev"] + ports: + - "127.0.0.1:1025:1025" + - "127.0.0.1:8025:8025" + security_opt: + - "no-new-privileges:true" + +volumes: + pgdata: + redisdata: + garage_meta: + garage_data: diff --git a/docs/BRANDING-CERTVIA.md b/docs/BRANDING-CERTVIA.md new file mode 100644 index 0000000..c02fb00 --- /dev/null +++ b/docs/BRANDING-CERTVIA.md @@ -0,0 +1,149 @@ +# Branding-Umstellung auf Certvia — Inventar & Umsetzung + +> Branch `dev-branding-certvia` (Basis `dev`) · Quelle: `Aufgabenpaket-Branding-Certvia.md` + `Certvia-Assets/` +> Leitplanke: **GEFIM bleibt Dachmarke** („Ein Produkt von GEFIM"), nur die **Produktmarke** wird Certvia. +> Reines Branding — **keine Funktionsänderung**, kein Umbau von Logik oder Datenmodell. + +--- + +## 1. Design-Tokens (verbindliche Referenz) + +**Markenfarben** (Logo, Print, Verläufe — `--brand-*`): + +| Rolle | Token | Hex | +|---|---|---| +| Violett (Marke) | `--brand-violet` | `#5d52a3` | +| Magenta (Akzent „via", Haken) | `--brand-magenta` | `#812d80` | +| Hellblau | `--brand-blue` | `#8dc4e0` | +| Anthrazit (Text/Headlines) | `--brand-anthracite` | `#3b3b3a` | +| Violett auf Dunkel | `--brand-violet-on-dark` | `#7d6fd6` | +| Magenta auf Dunkel | `--brand-magenta-on-dark` | `#d17bcf` | + +**UI Dark-Theme** (unverändert — **ist** die Certvia-Produktpalette, nicht „korrigieren"): +`--ui-primary #7d6fd6` · `--ui-primary-deep #5d52a3` · `--ui-blue #8dc4e0` · `--ui-magenta #b45bb0` · +`--bg-0 #0e1220` · `--bg-1 #141a2e` · `--elevated #1a2138` · `--panel rgba(30,38,64,.72)` · +`--panel-brd rgba(120,135,180,.18)` · `--foreground #e8ecf7` · `--muted-foreground #8b93ad` · +`--ok #39c07f` · `--warn #f0ad4e` · `--risk #ff6b6b` · Primär-Verlauf `linear-gradient(135deg,#5d52a3,#7d6fd6)` +· Fokus-Ring `rgba(125,111,214,.35)`. + +Single Source of Truth: **`src/app/globals.css`** (CSS) und **`src/lib/brand.ts`** (JS/TS — für alles, +was CSS-Variablen nicht auflösen kann: Canvas-/PNG-Export, Metadaten, künftige Dokument-Exporte). + +**Typografie:** Headlines/Wortmarke **Poppins**, Fließtext **Open Sans** — self-hosted (`src/app/fonts/`). + +--- + +## 2. Inventar (Story S0) + +### 2.1 Produktmarke → Certvia + +| Datei | Fundstelle | Maßnahme | Story | +|---|---|---|---| +| `src/app/globals.css` | `--gefim-violet/-deep/-blue/-magenta`, Kommentare „GEFIM-Theme" | Umbenannt auf `--brand-*` / `--ui-*`, Kommentare auf Certvia | S1/S9 | +| `src/app/globals.css` | Flächenfarben direkt als Hex (`#0e1220`, `#141a2e`, …) | Über `--bg-0`/`--bg-1`/`--elevated` geführt, semantische Tokens referenzieren sie | S1 | +| `src/components/risk-modals.tsx` | `bg-[#0e1220]` (Rest-Risiko-Marker, Legende) | → `bg-[var(--bg-0)]` | S1 | +| `src/app/(app)/risks/page.tsx` | `bg-[#0e1220]/75`, `hover:bg-[#0e1220]` (Heatmap-Chip) | → Token `--chip-overlay` / `var(--bg-0)` | S1 | +| `src/components/dependency-graph.tsx` | `#8dc4e0`, `#ff6b6b`, `#141a2e`, `#0e1220`, `#4a5372`, `#8b93ad` | CSS-Vars wo möglich; PNG-Export nutzt `BRAND.ui` aus `src/lib/brand.ts` (html-to-image löst keine CSS-Vars auf) | S1 | +| `public/gefim-logo.png` | Produktlogo in Sidebar + Login | Verschoben nach `public/assets/logo/gefim-logo.png`, dient nur noch der **Dachmarke** | S2 | +| `src/app/(app)/layout.tsx` | Sidebar-Logo `/gefim-logo.png`, Alt-Text „GEFIM …" | `` über den Branding-Resolver | S2/S8 | +| `src/app/login/page.tsx` | Logo `/gefim-logo.png`, Alt-Text | Certvia-Lockup + Tagline + Dachmarken-Fußnote | S2/S7 | +| `src/app/platform/login/page.tsx` | kein Logo | Certvia-Lockup + „Plattform-Administration" | S2/S7 | +| `src/app/(platform)/layout.tsx` | `ShieldCheck` + „ISMS · Plattform-Administration" | Certvia-Mark + „Certvia · Plattform-Administration" | S2/S3 | +| `src/app/layout.tsx` | `title: "ISMS-Tool"`, keine Icons/OG/Manifest | Vollständige Certvia-Metadaten inkl. Icons, Manifest, `themeColor` | S3 | +| `src/app/favicon.ico` | Next-Default-Favicon | Entfernt; Icons laufen über `public/favicon/` + `metadata.icons` | S2 | +| `messages/de.json`, `messages/en.json` | `common.appName` = „ISMS-Tool"/„ISMS Tool" | → „Certvia" (+ `appTagline`, `appByline`) | S3 | +| `src/server/mfa.ts` | TOTP-Issuer `"ISMS-Tool · Plattform"` | → `"Certvia · Plattform"` | S3 | +| `src/components/ui/button.tsx` | Kommentar „GEFIM-Verlauf" | → „Certvia-Verlauf" | S9 | +| `src/components/mockup-ui.tsx` | Kommentar-Referenz auf Mockup-Datei | Formulierung entschärft (Dateiname bleibt, s. u.) | S9 | +| `src/lib/control-titles.ts` | Kommentar „aus dem GEFIM-Mockup übernommen" | → neutral „aus dem UI-Mockup" | S9 | +| `src/app/(app)/settings/page.tsx` | Hinweis „Logo-Upload folgt in Phase 2" | Ergänzt um Certvia-Default-Aussage | S8 | +| `src/proxy.ts` | Matcher schloss `.webmanifest` nicht aus | `/site.webmanifest` lieferte die Login-HTML statt JSON → Endung ergänzt (siehe §5) | S3 | + +### 2.2 Dachmarke GEFIM → bleibt bewusst erhalten + +| Ort | Grund | +|---|---| +| `public/assets/logo/gefim-logo.png` | Dachmarken-Logo für „Ein Produkt von GEFIM" | +| `src/components/brand/powered-by-gefim.tsx` | Neue Komponente, die genau diesen Hinweis rendert (Login, Plattform-Login, Print-/Export-Fußzeile, Mail-Footer) | +| `docs/ISMS-*-GEFIM.html`, Verweise in `README.md`/`AGENTS.md`/`docs/SPEC.md` | Historische Mockups/Spezifikation — Projektartefakte, keine Produkt-UI | +| `prisma/seed.ts` (`ORG_NAME` „GEFIM Demo GmbH") | **Demo-Mandantendaten** (fiktiver Kunde), nicht der Produktname | +| `prisma/import-managed.ts` (`portal.gefim.example`) | Demo-Registerzeile, nicht der Produktname | + +Nach der Umstellung liefert `rg -i "gefim"` ausschließlich diese Kategorien. + +--- + +## 3. Umgesetzte Stories + +| Story | Inhalt | Status | +|---|---|---| +| **S0** | Inventar (dieses Dokument) | ✅ | +| **S1** | Token-Zentralisierung `--brand-*` / `--ui-*`, `src/lib/brand.ts`, hartkodierte Farben ersetzt | ✅ | +| **S2** | Assets eingebunden, ``, Favicon/PWA-Icons, Sidebar + beide Logins | ✅ | +| **S3** | App-Name/Meta/OG/Manifest/i18n/MFA-Issuer auf Certvia | ✅ | +| **S4** | Poppins + Open Sans self-hosted bestätigt (waren es bereits), Fallback-Stack + `swap` geprüft | ✅ | +| **S7** | Login, Plattform-Login, Change-Password, Enroll-MFA, Konto-deaktiviert, 404, 500 gebranded | ✅ | +| **S9** | Produkt-Referenzen bereinigt, Dachmarke belassen | ✅ | +| **S5** | Branding-Layer für Dokument-/Export-CD (`src/lib/brand.ts` + Print-Stylesheet) | ✅ (Andockpunkt) | +| **S8** | Branding-Resolver mit Certvia-Default, Custom überschreibt nur wenn gesetzt | ✅ | +| **S6** | Brandfähige E-Mail-Template-Basis (SMTP selbst folgt in Paket 4) | ✅ (Basis) | + +--- + +## 4. Wo liegt was (neu) + +| Pfad | Inhalt | +|---|---| +| `src/lib/brand.ts` | Marken-/UI-Farben als JS-Konstanten, Produktname/Tagline/Byline, Asset-Pfade, `resolveTenantBranding()` | +| `src/lib/document-brand.ts` | Dokument-CD (helles Theme, Kopf-/Fußzeilen-Bausteine) — Andockpunkt für DOCX/PDF | +| `src/lib/email-brand.ts` | Brandfähige HTML-/Text-Mail-Basis für Paket 4 | +| `src/components/brand/certvia-logo.tsx` | `` als Inline-SVG | +| `src/components/brand/tenant-brand.tsx` | Mandanten-Marke mit Certvia-Fallback | +| `src/components/brand/powered-by-gefim.tsx` | Dachmarken-Hinweis inkl. GEFIM-Logo | +| `public/assets/logo/` | Certvia-SVGs/PNGs + GEFIM-Dachmarkenlogo | +| `public/favicon/`, `public/favicon.ico`, `public/site.webmanifest` | App-Icons und PWA-Manifest | +| `docs/branding/` | Aufgabenpaket + Logo-README aus dem Design-Paket | +| `src/app/globals.css` (`@media print`) | Druck-/Dokument-CD | + +--- + +## 5. Beim Einbau aufgefallen (Abweichungen vom Aufgabenpaket) + +- **Lockup-SVG trägt Poppins jetzt eingebettet.** `public/assets/logo/certvia-lockup-positiv.svg` + enthält Poppins 300 + 700 als woff2-Data-URI (≈22 KB). Damit erscheint die Wortmarke auch + außerhalb der App korrekt (Druck, Export, Mail) — der offene Punkt „Text in Pfade wandeln" aus + `docs/branding/README-Logo.md` ist damit erledigt. Geometrie und Farben sind unverändert. + In der App rendert `` das Zeichen ohnehin inline und nutzt die App-Schrift direkt. +- **`/site.webmanifest` war nicht erreichbar.** Der Route-Gate-Matcher in `src/proxy.ts` nahm nur + `svg|png|jpg|ico` aus — für `.webmanifest` lieferte der Server die Login-Seite statt JSON, das + PWA-Manifest wäre also wirkungslos geblieben. Endung ergänzt. Bewusst **keine** Verzeichnis- + Ausnahme für `assets/`: das ist zugleich die App-Route des Asset-Inventars und bleibt hinter dem + Gate (nachgeprüft: `/assets`, `/assets/xyz` → 307 auf `/login`). +- **`src/app/favicon.ico` entfernt.** Die Datei-Konvention von Next.js und eine `public/favicon.ico` + schließen sich gegenseitig aus; die Icons laufen jetzt vollständig über `metadata.icons`. +- **404-/500-Seiten neu angelegt** (`src/app/not-found.tsx`, `src/app/error.tsx`) — es gab bisher + keine. Sie erscheinen für angemeldete Nutzer; anonyme Aufrufe fängt weiterhin das Login-Gate ab. + +### Kontrast (WCAG AA, geprüft) + +| Kombination | Kontrast | Bewertung | +|---|---|---| +| Magenta `#812d80` auf Weiß (Wortmarke/Print) | 8,0 : 1 | AA + AAA | +| Magenta `#d17bcf` auf Karte `#141a2e` | 6,1 : 1 | AA | +| Magenta `#d17bcf` auf Seitengrund `#0e1220` | 6,6 : 1 | AA | + +--- + +## 6. Bewusste Abgrenzungen + +- **UI-Palette unverändert.** Die Dark-Theme-Farben wurden nur konsolidiert/umbenannt, nicht geändert. + `--brand-violet` (`#5d52a3`) gilt für Logo/Print/Verläufe, `--ui-primary` (`#7d6fd6`) für Interaktion. +- **Kein Light-Mode.** Die App ist bewusst dark-only; `` existiert für + Dokument-/Druck-/Mail-Kontexte, wird in der UI aber nicht verwendet. +- **Poppins 400** ist nicht als woff2 im Repo (vorhanden: 300/500/600/700). Aktuell nutzt nichts + Poppins 400 — Headlines laufen auf 600/700, die Wortmarke auf 300/700. Sollte 400 gebraucht werden, + muss die woff2 ergänzt werden; ein CDN-Fetch bleibt ausgeschlossen. +- **Logo-Upload je Mandant** braucht Objektspeicher (Admin Phase 2). Der Resolver ist bereits darauf + vorbereitet (`logoUrl` optional), das Feld existiert im Schema noch nicht — bewusst keine Migration. +- **DOCX/PDF-Export** existiert noch nicht. S5 liefert den Branding-Layer (Konstanten + Kopf-/Fußzeile + + Print-CSS), an den das Export-Feature andockt. diff --git a/docs/DEPLOY-COOLIFY.md b/docs/DEPLOY-COOLIFY.md new file mode 100644 index 0000000..82b5c5d --- /dev/null +++ b/docs/DEPLOY-COOLIFY.md @@ -0,0 +1,123 @@ +# Deployment: Testserver via Coolify (intern) + +> Zielumgebung: interner Coolify-Host (`192.168.1.207`), Docker-Compose-Stack, +> HTTP über eine `*.sslip.io`-Domain (kein öffentliches TLS). +> Ergänzt `docs/HANDOVER-DEVOPS.md`. Deploy-Datei: `docker-compose.coolify.yml`. + +## Architekturüberblick (Coolify) + +- Coolify deployt den **Compose-Stack** aus diesem Repo und übernimmt **Reverse-Proxy + Routing** — die App wird **nicht** per Host-Port exponiert. +- Services: `migrate` (Init-Job) → `app` (Next.js standalone) + `postgres` (pgvector), `redis`, `garage` (Objektspeicher) + `garage-provision` (Init-Job). +- **Migrationen** laufen als eigener Init-Job `migrate` (`prisma migrate deploy`, schlanke **`migrate`-Stage** ohne `next build`) **vor** `app` — der App-Container migriert selbst nicht. +- **Objektspeicher Garage** (ersetzt MinIO, Community EOL): S3-kompatibel, Single-Node. Buckets/Keys legt NICHT die S3-API an, sondern der Init-Job `garage-provision` (Admin-API, idempotent) **vor** `app`. Details/Cutover: eigener Abschnitt unten. +- **Redis** läuft mit `requirepass` (F-18): `REDIS_PASSWORD` als Coolify-Env setzen und in die `REDIS_URL` einsetzen (`redis://:@redis:6379`). +- **Netzsegmentierung** (F-18): `postgres`/`redis`/`garage`/`migrate` liegen im internen Netz (`internal: true`, kein Egress); nur `app` ist zusätzlich im default-Netz (Coolify-Proxy). Garage wird nicht per Traefik/Host-Port exponiert. +- **Secrets/Config** kommen aus den **Coolify-Env-Variablen** (Referenz: `.env.coolify.example`), nicht aus einer committeten `.env`. + +## 1. Gitea mit Coolify verbinden (Deploy Key) + +SSH ist erreichbar (`git@…sslip.io:22`), daher Deploy-Key: + +1. **Coolify → Keys & Tokens → Private Keys**: SSH-Key generieren (oder beim Anlegen der Ressource „Private Repository (deploy key)“ automatisch). Öffentlichen Key kopieren. +2. **Gitea → Repo `msolarczek/ISMS-Tool` → Settings → Deploy Keys → Add Deploy Key**: Key einfügen, nur Lesezugriff. +3. Repo-URL in Coolify (SSH): + `git@gitea-vkbhbn2qdkz5ppk9q4qgb0tn.192.168.1.207.sslip.io:msolarczek/ISMS-Tool.git` + +## 2. Ressource anlegen + +1. Projekt/Environment wählen → **+ New → Private Repository (deploy key)**. +2. Repo `ISMS-Tool`, **Branch `devops/coolify-testserver`** (nach erfolgreichem Test → `main`). +3. **Build Pack: Docker Compose**, **Compose Location: `docker-compose.coolify.yml`**. + +## 3. Environment-Variablen + +Werte aus `.env.coolify.example` in Coolify eintragen. Kritisch: + +- Hostnamen = Compose-Service-Namen: `postgres`, `redis`, `garage` (nicht `localhost`); `S3_ENDPOINT=http://garage:3900`. +- `AUTH_SECRET` frisch: `openssl rand -base64 32`. +- `AUTH_URL` = exakt die in Schritt 4 vergebene App-Domain (`http://…`). +- **Garage** (siehe Abschnitt unten): `GARAGE_RPC_SECRET` + `GARAGE_ADMIN_TOKEN` (je `openssl rand -hex 32`), sowie `S3_ACCESS_KEY` = `GK`+24 Hex (`echo "GK$(openssl rand -hex 12)"`) und `S3_SECRET_KEY` = `openssl rand -hex 32`. Alle **literal** setzen (nicht via `${…}` — Coolify-Interpolationsfalle). + +## 4. Domain & HTTP + +- Beim Service `app` unter **Domains** die `*.sslip.io`-Domain übernehmen, Schema **`http://`**. +- Dieselbe Domain als `AUTH_URL` setzen (sonst schlägt der NextAuth-Login fehl). + +## 5. Persistenz + +Named Volumes müssen als Persistent Storage erkannt sein — v. a. **`pgdata`** (sonst Datenverlust bei Redeploy) und **`garage_meta`** (Bucket-/Key-/Layout-Definitionen — ohne meta sind die Objektdaten in `garage_data` nicht adressierbar). Ebenso `garage_data`, `redisdata`, `backups`. **`garage_meta` in die Host-Backup-Strategie aufnehmen** (analog `pgdata`). + +## 6. Deploy + +**Deploy** starten. Reihenfolge: `postgres` (healthy) → `migrate` (läuft einmalig durch) → `app` (startet erst nach erfolgreichem Migrate). Logs von `migrate`/`app` bei Fehlern prüfen. + +## 7. Demo-Admin anlegen (einmalig, Testserver) + +Der Demo-Seed läuft nicht automatisch. Im Coolify-**Terminal** des `migrate`-Containers (builder-Image, hat `tsx`): + +``` +npx tsx prisma/seed.ts +``` + +Login danach: `admin@demo.example` / `Demo1234!`. + +> Produktiv: **kein** Demo-Seed. Stattdessen einmaliger Bootstrap des Plattform-Admins +> (`provisionTenant({ admin.isPlatformAdmin: true })`) — Skript noch zu erstellen +> (siehe `docs/HANDOVER-DEVOPS.md` §4). + +## 8. Smoke-Test + +Über die App-Domain: Login, Admin-Konsole, eine Modul-Seite. + +## Redeploy / Migrationen-Nachziehen + +Jeder Coolify-Redeploy baut neu und lässt `migrate` erneut laufen (`migrate deploy` ist idempotent — nur neue Migrationen werden angewandt). App startet erst nach erfolgreichem Migrate. + +## Von Test zu Produktiv (Delta) + +- `AUTH_SECRET`, DB-Passwörter und die **Garage-Secrets** (`GARAGE_RPC_SECRET`, `GARAGE_ADMIN_TOKEN`, `S3_ACCESS_KEY`/`S3_SECRET_KEY`) neu/aus Secret-Store; eigene Domain + gültiges TLS. +- **Kein** Demo-Seed; Erst-Superadmin per Bootstrap-Skript. +- Backups (`pg_dump`/Volume-Snapshots inkl. **`garage_meta`**) + Restore-Test, Monitoring/Alerting. +- Ggf. ≥ 2 `app`-Replicas hinter dem Coolify-Proxy. + +## Objektspeicher (Garage) — Cutover, Provisioning & Rollback + +Ablösung von MinIO (Community EOL) durch **Garage** (S3-kompatibel, aktiv gepflegt, +Single-Node). Konzept: `docs/KONZEPT-garage-migration.md`. Es gibt **keine produktiven +Daten** → **Neu-Deploy statt Datenmigration** (kein rclone, kein Wartungsfenster). + +**Konfig-Bausteine** +- `deploy/garage.toml` (eingecheckt, **secret-frei**): `replication_factor=1`, + `s3_region=us-east-1`, S3-API `:3900`, Admin-API `:3903`. `rpc_secret`/`admin_token` + liest der Daemon aus der Env (`GARAGE_RPC_SECRET`/`GARAGE_ADMIN_TOKEN`). +- Volumes: `garage_meta` (**kritisch**, ins Host-Backup) + `garage_data`. +- Init-Job `garage-provision` (`scripts/garage-provision.ts`, Admin-API, **idempotent**): + Layout → Bucket `isms-documents` → Access-Key **importieren** (aus `S3_ACCESS_KEY/…`) + → Rechte read/write. Läuft bei jedem Deploy; „already exists“ = Erfolg. Ohne + `GARAGE_ADMIN_TOKEN` No-op. Loggt **keine** Secrets. + +**Cutover-Runbook (Test-Instanz)** +1. Compose enthält bereits `garage` + `garage-provision`; der alte `minio`-Service ist + auskommentiert (Rollback-Netz) und wird erst nach Abnahme entfernt. +2. Coolify-Env **literal** setzen (nicht `${…}`): `S3_ENDPOINT=http://garage:3900`, + `S3_REGION=us-east-1`, `S3_BUCKET=isms-documents`, `GARAGE_RPC_SECRET`, + `GARAGE_ADMIN_TOKEN`, `S3_ACCESS_KEY` (`GK`+24 Hex), `S3_SECRET_KEY` (64 Hex). +3. Deploy. Reihenfolge: `garage` (healthy: `/garage status`) → `garage-provision` + (legt Layout/Bucket/Key/Rechte an) → `app`. Optionaler DB-Reset nur, falls alte + Objekt-Referenzen stören (bei frischer/geseedeter Instanz unnötig). +4. Abnahme (§ KONZEPT §9): Upload → Download (`/files/[...key]`) → Backup-Export `.cvb` + + Download → DSGVO-ZIP → Restore mit Mandanten-Isolation → Backup-Historie List/ + Aufräumen → Negativfall „fehlender Bucket“ = sprechender Fehler. +5. **`garage_meta`** in der Host-Backup-Strategie bestätigen. Erst danach den + `minio`-Block **und** das Volume `miniodata` aus `docker-compose.coolify.yml` entfernen. + +**Rollback** (unkritisch, keine Prod-Daten): `garage`/`garage-provision` wieder aus-, +den auskommentierten `minio`-Block wieder einkommentieren und die alten `S3_*`/ +`MINIO_*`-Env setzen; neu deployen. Solange `minio` + `miniodata` noch existieren, ist +das ein reiner Compose-/Env-Wechsel. + +**Provisioning erneut anstoßen / debuggen**: Im Coolify-Terminal eines Containers mit +`tsx` (`migrate`-Image) `npx tsx scripts/garage-provision.ts` erneut laufen lassen +(idempotent). „Container weg ohne Logs“ (Coolify entfernt fehlgeschlagene Container +sofort): Provisioning-Ausgabe zusätzlich in eine Datei spiegeln, z. B. +`npx tsx scripts/garage-provision.ts 2>&1 | tee /tmp/garage-provision.log`. diff --git a/docs/DEPLOY-PROD-CONTABO.md b/docs/DEPLOY-PROD-CONTABO.md new file mode 100644 index 0000000..cb855dd --- /dev/null +++ b/docs/DEPLOY-PROD-CONTABO.md @@ -0,0 +1,485 @@ +# Deployment: Produktivserver (Contabo-VPS via Coolify) + +> Zielumgebung: öffentlicher Contabo-VPS, eigene Coolify-Instanz, Git (Gitea) auf +> demselben VPS, Domain **app.certvia.de** mit echtem Let's-Encrypt-TLS. +> Ergänzt `docs/DEPLOY-COOLIFY.md` (Testserver). Deploy-Datei: `docker-compose.coolify.yml`. + +## Unterschiede zum Testserver + +| Aspekt | Test (intern) | Produktiv (Contabo) | +|--------|---------------|---------------------| +| Erreichbarkeit | intern, HTTP, sslip.io | öffentlich, **HTTPS**, `app.certvia.de` | +| Git-Quelle | internes Gitea | **Gitea auf dem VPS** (Release-Push) | +| Erst-Admin | Demo-Seed (`RUN_DEMO_SEED=true`) | **Bootstrap-Admin** (`BOOTSTRAP_ADMIN=true`), **kein** Demo-Seed | +| Secrets | Testwerte | **frische, starke** Secrets | +| Backups | optional | **Pflicht** (pg_dump + Restore-Test) | +| Branch | `dev` | `main` | + +--- + +## Phase 1 — VPS-Grundlage + +1. **Contabo-VPS** bereitstellen — **≥ 8 GB RAM** empfohlen (Next-Build ~1 GB + Stack). Bei weniger RAM zwingend Swap: + ```bash + fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile + echo '/swapfile none swap sw 0 0' >> /etc/fstab + free -h + ``` +2. **Grundhärtung**: System aktualisieren, SSH-Key-Login (Passwort-Login aus), unattended-upgrades. +3. **Firewall** (ufw): nur benötigte Ports offen — `80`, `443`, SSH, sowie der Gitea-SSH-Port (s. Phase 2). +4. **Coolify installieren** (offizielles Installskript) — eigene, unabhängige Instanz. + +## Phase 2 — Gitea auf dem VPS + +5. Gitea als **Coolify-Ressource** (One-Click/Compose) aufsetzen, eigene Subdomain (z. B. `git.certvia.de`), TLS via Coolify. +6. Repo `ISMS-Tool` in diesem Gitea anlegen. +7. Lokal ein **zweites Remote** hinzufügen und beim Release `main` dorthin pushen: + ```bash + git remote add prod https://git.certvia.de//ISMS-Tool.git + git push prod main + ``` + (Das ist der bewusste „Release-Push" — Prod deployt nur, was hier landet.) + +## Phase 3 — DNS & Domain + +8. Bei eurem DNS für `certvia.de` einen **A-Record** `app.certvia.de` → Contabo-IP anlegen (ebenso `git.certvia.de`). +9. Coolify vergibt/prüft danach automatisch das Let's-Encrypt-Zertifikat (VPS ist öffentlich erreichbar). + +## Phase 4 — App-Ressource (Prod) in Coolify + +10. **+ New Resource** → Git-Quelle = das **VPS-Gitea** (Deploy-Key), Repo `ISMS-Tool`, **Branch `main`**. +11. **Build Pack: Docker Compose**, **Compose Location: `docker-compose.coolify.yml`**. +12. **Domain** beim Service `app` = `https://app.certvia.de:3000` (Port 3000), Schema **https**. +13. **Environment-Variablen** aus `.env.prod.example` setzen (Runtime-Variablen). Kritisch: + - Alle Secrets **frisch** (`AUTH_SECRET` neu: `openssl rand -base64 32`; neue DB-/MinIO-Passwörter). + - `AUTH_URL=https://app.certvia.de` (exakt die App-Domain). + - `RUN_DEMO_SEED=false` (bzw. weglassen). + - **Bootstrap** (erster Deploy): `BOOTSTRAP_ADMIN=true` + `BOOTSTRAP_ADMIN_EMAIL/PASSWORD/NAME` + `BOOTSTRAP_TENANT_NAME/SLUG`. +14. **Persistent Storage** prüfen — v. a. `pgdata` (sonst Datenverlust bei Redeploy). + +## Phase 5 — Erster Deploy & Bootstrap + +15. **Deploy**. Ablauf: `postgres` (healthy) → `migrate` (migriert **und** legt via `BOOTSTRAP_ADMIN=true` den Erst-Admin an) → `app`. +16. In den **`migrate`-Logs** prüfen: `>> Bootstrap-Admin läuft…` → `✔ Bootstrap fertig: Mandant … + Plattform-Admin … angelegt.` +17. **Login** unter `https://app.certvia.de` mit den `BOOTSTRAP_ADMIN_*`-Zugangsdaten → **Passwort sofort ändern**. +18. Optional danach `BOOTSTRAP_ADMIN` auf `false` (das Skript ist idempotent, es schadet aber nicht, es an zu lassen). + +## Phase 6 — Backups & Betrieb (vor „echtem" Go-Live) + +19. **Postgres-Backups**: regelmäßiger `pg_dump` (oder Coolify-DB-Backup nach S3) + **Restore-Test** dokumentieren. `pgdata` ist das kritische Volume. +20. **MinIO-Backup**, sobald Datei-/Logo-Upload aktiv ist. +21. **Monitoring/Alerting**: App-Healthcheck ist im Compose vorhanden; zusätzlich Uptime-Check auf `https://app.certvia.de` und Log-Aggregation einrichten. +22. **Updates**: Betriebssystem/Coolify/Images regelmäßig aktualisieren. + +## Phase 7 — Auto-Deploy (optional) + +23. Gitea-Webhook (VPS-Gitea → Coolify) mit **Branch-Filter `main`**. Da Gitea und Coolify auf demselben Host sind, ggf. `GITEA__webhook__ALLOWED_HOST_LIST` weit genug setzen (vgl. Testserver-Erfahrung). + +--- + +## Release-Fluss (Zusammenfassung) + +``` +Feature-Branch → dev # Entwicklung, Auto-Deploy Testserver +dev → main # Release-Merge (nach Test-Freigabe) +git push prod main # Release-Push ins VPS-Gitea → Prod-Deploy +``` + +## Row Level Security scharfschalten (F-04) + +Postgres RLS ist als zweite Verteidigungslinie definiert (Policy `tenant_isolation` +je Mandanten-Tabelle) und mit der Migration `rls_enforce` unter +`FORCE ROW LEVEL SECURITY` + `WITH CHECK` scharf gestellt. Sie wird **env-gesteuert** +aktiviert (`RLS_ENFORCED`), Default ist **aus** (Owner-Betrieb wie bisher). + +**Wie es funktioniert:** Bei `RLS_ENFORCED=true` verbindet sich der App-Prozess als +eingeschränkte Rolle `isms_app` (NOBYPASSRLS) über `RLS_DATABASE_URL` und setzt +`app.tenant_id` transaktionslokal pro Operation. Für diese Rolle greifen die +Policies. Migrationen, Seed/Bootstrap und der mandantenübergreifende Login-Lookup +laufen weiter über die **Owner-`DATABASE_URL`**. + +**Scharfschalten (einmalig):** + +1. App-Rolle mit LOGIN + starkem Passwort versehen (nur einmal, kein Secret ins Repo): + ```bash + docker exec -it psql -U isms -d isms \ + -c "ALTER ROLE isms_app WITH LOGIN PASSWORD '';" + ``` +2. In Coolify die Env-Variablen setzen: + - `RLS_ENFORCED=true` + - `RLS_DATABASE_URL=postgresql://isms_app:@postgres:5432/isms?schema=public` +3. App-Service neu deployen. Fehlt `RLS_DATABASE_URL` bei aktivem Flag, bricht die + App bewusst beim Start ab (fail secure). + +> **Warnung — Owner-Rolle muss BYPASSRLS/Superuser sein.** Die in `DATABASE_URL` +> genutzte Owner-/Migrate-Rolle (`isms`) MUSS `BYPASSRLS` bzw. Superuser sein, +> sonst sähe der Login (mandantenübergreifend) **keine** Nutzer und Migrationen +> könnten fehlschlagen. FORCE ist für diese Rolle unschädlich, weil BYPASSRLS die +> RLS auch unter FORCE umgeht. +> +> **Warnung — ohne Kontext = null Zeilen.** `RLS_ENFORCED=true` NIE ohne korrektes +> `RLS_DATABASE_URL` setzen: eine RLS-Rolle ohne gesetzten `app.tenant_id` sieht +> gar keine Zeilen. Das Setzen des Kontexts übernimmt `dbForTenant` automatisch. + +Nachweis der Korrektheit lokal: `npx tsx scripts/test-rls-enforcement.ts`. + +## Host-Encryption at-rest — Daten-Volume (`pgdata` + MinIO) + +> Umsetzung der Härtung §2 (`docs/KONZEPT-haertung.md`). **Ops-Runbook, kein App-Code.** +> Schützt gegen **physischen Plattendiebstahl / VPS-Decommission** — die Volumes liegen +> sonst im Klartext auf der Contabo-Platte (`pgvector`-Community-Postgres hat **kein TDE**). +> **Kein** Schutz gegen Live-Kompromittierung des laufenden Servers (dafür greifen +> App-Feld-Encryption, RLS, Zugriffskontrollen) — im Betrieb ist das Volume im RAM entschlüsselt. + +**Prinzip:** Ein **LUKS/dm-crypt**-Container (dm-crypt/`cryptsetup`) bzw. ein +**provider-verschlüsseltes Block-Volume** trägt das gesamte Daten-Volume. Coolifys +Persistent-Storage (`pgdata`, MinIO-Daten, ggf. Redis-AOF) wird auf dieses +verschlüsselte Volume gelegt — damit sind `pgdata` **und** MinIO in einem Rutsch gedeckt. + +**Einrichtung (einmalig, vor dem ersten Deploy mit echten Daten):** + +1. Separates Block-Volume/Partition bereitstellen (z. B. `/dev/sdb`) — **nicht** das Root-FS. +2. LUKS-Container anlegen und öffnen: + ```bash + cryptsetup luksFormat --type luks2 /dev/sdb # Passphrase vergeben (s. u.) + cryptsetup open /dev/sdb cryptdata # -> /dev/mapper/cryptdata + mkfs.ext4 /dev/mapper/cryptdata + mkdir -p /srv/cryptdata && mount /dev/mapper/cryptdata /srv/cryptdata + ``` +3. Coolifys Datenwurzel (bzw. die betroffenen Named-Volumes/Bind-Mounts für `pgdata` + und MinIO) auf `/srv/cryptdata/...` legen und die Compose-`volumes` dorthin zeigen lassen. +4. **Passphrase / Key-File** ausschließlich im **Org-Passwortmanager** hinterlegen + (Eintrag im `docs/SECRETS-REGISTER.md` führen) + versiegelte Offline-Kopie. **Nie** ins Repo, + nie ins Backup-Bucket. + +**Boot-Unlock (dokumentierte Entscheidung nötig — Betreiber wählt):** + +- **A) Manuelles Unlock (empfohlen für Einzel-VPS, höchster Schutz):** Nach jedem Reboot + meldet sich ein Operator per SSH an und führt `cryptsetup open` + `mount` (bzw. ein + `systemd`-Gate vor den Docker-/Coolify-Start) aus. Kein Key auf der Platte → Diebstahl + der Platte nützt nichts. Nachteil: **kein unbeaufsichtigter Reboot** (Downtime bis Unlock). +- **B) Key-File auf getrenntem Medium / Netz-Unlock:** `crypttab`-Key-File auf einem separaten, + nicht mit der Platte gestohlenen Träger, oder **dracut/clevis + Tang** (Network-Bound Disk + Encryption) für auto-unlock, solange der Tang-Server erreichbar ist. Komfortabler, + aber der Angreifer, der Platte **und** Key/Tang-Zugang hat, gewinnt. + +> **Betreiber-Entscheidung dokumentieren:** A oder B, wer die Passphrase hält, und wie der +> Reboot-Ablauf aussieht (Runbook-Schritt „Nach Reboot: Volume entsperren, dann Coolify starten"). +> Ohne Unlock startet Postgres/MinIO nicht — das ist beabsichtigt (fail-secure). + +## Verschlüsselte Backups — pgBackRest / age / restic + +> Umsetzung der Härtung §3 + Backup-Konzept §9 (`docs/KONZEPT-backup-restore.md`). +> **Entscheidung:** **client-seitige AES-256-Verschlüsselung mit einem Schlüssel pro Umgebung** +> — das Artefakt ist verschlüsselt, **bevor** es S3/MinIO erreicht (at-rest + in-transit + +> zero-knowledge vom Speicher). **Nicht** allein auf Storage-SSE verlassen (SSE gern zusätzlich). +> Konsistent zur bestehenden App-Verschlüsselung (TOTP AES-256-GCM, Backup-Export AES-256-GCM). + +**Schichten (je Umgebung getrennte Schlüssel):** + +| Schutzobjekt | Werkzeug | Schlüssel | +|---|---|---| +| Cluster-Backup (Postgres, WAL/Base) | **pgBackRest** `repo-cipher-type=aes-256-cbc` + `repo-cipher-pass` → S3/MinIO | pgBackRest-Repo-Key je Umgebung | +| Per-Tenant-Export + DSGVO-Pakete | **`age`** (X25519, encrypt-then-upload) | `age`-Keypair je Umgebung | +| MinIO-Dateien (Uploads/Logos) | **restic** (eingebaute AES-256-Verschlüsselung) | restic-Repo-Passwort je Umgebung | + +**pgBackRest (Beispiel `pgbackrest.conf`, Repo auf MinIO/S3):** +```ini +[global] +repo1-type=s3 +repo1-s3-endpoint= +repo1-s3-bucket=certvia-pgbackrest-prod # eigener Bucket, NICHT der App-Bucket +repo1-s3-key= # nur Backup-Zugang, getrennt vom App-MinIO-User +repo1-s3-key-secret= +repo1-cipher-type=aes-256-cbc +repo1-cipher-pass= # aus Passwortmanager, NIE im Bucket +repo1-retention-full=4 # Retention: s. u. +[certvia] +pg1-path=/srv/cryptdata/pgdata +``` + +**age (Per-Tenant-/DSGVO-Artefakte):** +```bash +age-keygen -o /root/age-prod.key # Private Key -> Passwortmanager + offline +# Public Recipient (age1...) als Env/Config für die Backup-Jobs: +age -r age1 -o export.tenant.age export.tenant.tar +``` + +**restic (MinIO-Objektdaten):** +```bash +export RESTIC_REPOSITORY=s3:/certvia-restic-prod +export RESTIC_PASSWORD= # aus Passwortmanager +restic backup /srv/cryptdata/minio +restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune +``` + +**Verdrahtung in Coolify / Betrieb:** + +- **Scheduling:** Coolify-**Scheduled Task / Cron** je Job (pgBackRest full+incr, `age`-Export, + restic) — Zugangsdaten als Coolify-Env-Secrets, **nicht** im Compose committen. +- **Retention je Schicht dokumentieren** (DR-WAL/Base, Per-Tenant-Snapshots, DSGVO-Exporte) + und dem **DSB** vorlegen — Löschfristen ergeben sich aus der DSGVO-Aufbewahrung. +- **Getrennte Buckets/Zugänge:** Backup-Repos liegen in **eigenen** Buckets mit **eigenem** + Zugang, nie im App-MinIO-Bucket und nie zusammen mit den Schlüsseln. +- **Restore-Test regelmäßig + dokumentiert** (der Prod-Runbook fordert das bereits für `pgdata`, + Phase 6): mindestens quartalsweise eine Wiederherstellung in eine Wegwerf-Umgebung, Ergebnis + protokollieren. Ein ungetestetes Backup gilt als kein Backup. + +**Bezug zur App-Backup-Engine:** Der in `dev` integrierte App-Export/Restore verschlüsselt +Artefakte bereits **client-seitig mit AES-256-GCM** über `BACKUP_ENC_KEY` (Fallback `AUTH_SECRET`), +**ein Key pro Umgebung** (Backup-Konzept §9). Umgebungs-Secrets (Pepper/`MFA_ENC_KEY`/`BACKUP_ENC_KEY`) +liegen **nicht** im Artefakt; der Restore setzt Owner=Superuser voraus (`session_replication_role`). +pgBackRest/`age`/restic sind die **Ops-Ebene darunter** (Cluster/Host/Objektspeicher) — +dieselbe Grundregel „ein Schlüssel pro Umgebung, getrennt vom Artefakt" gilt durchgängig. + +## Schicht A — Cluster-Disaster-Recovery mit PITR (Go-Live-Runbook) + +> Umsetzung Backup-Konzept §2 (`docs/KONZEPT-backup-restore.md`). **Ops-Runbook, kein App-Code.** +> Schicht A deckt den **gesamten** Cluster ab — auch die **globalen** Tabellen (`Identity`/ +> Credentials, Kataloge, `PlatformAdmin`), die die mandanten-scoped App-Engine (Schicht B) +> bewusst NICHT anfasst. Zweck: Totalausfall / Ransomware / menschlicher Massenfehler → +> „DB auf Zeitpunkt T" (Point-in-Time-Recovery). + +**Bausteine:** **pgBackRest** (empfohlen) oder **wal-g** — periodisches **Voll-/Inkrement-Backup** +plus kontinuierliches **WAL-Archiving** nach S3/MinIO, verschlüsselt (`repo-cipher`). Erst das +WAL-Archiv macht PITR möglich (Replay bis zu einem Zeitpunkt zwischen zwei Base-Backups). + +### A.1 Repo-Config (Ergänzung zu `pgbackrest.conf` oben) + +```ini +[global] +# ... (repo1-* wie im Abschnitt „Verschlüsselte Backups" oben) ... +repo1-retention-full=4 # 4 Voll-Backups vorhalten (s. Retention-Tabelle) +repo1-retention-archive=8 # WAL für so viele Full-Sets behalten (PITR-Fenster) +repo1-retention-archive-type=full +start-fast=y +archive-async=y # asynchrones Archiving (Durchsatz/latenztolerant) +spool-path=/var/spool/pgbackrest + +[certvia] +pg1-path=/srv/cryptdata/pgdata +``` + +### A.2 WAL-Archiving in Postgres aktivieren (`postgresql.conf`) + +```ini +archive_mode = on +archive_command = 'pgbackrest --stanza=certvia archive-push %p' +wal_level = replica +max_wal_senders = 3 +``` + +```bash +# Stanza einmalig anlegen + prüfen, dann erstes Voll-Backup: +pgbackrest --stanza=certvia stanza-create +pgbackrest --stanza=certvia check +pgbackrest --stanza=certvia --type=full backup +# Zeitplan (Coolify Scheduled Task / cron): +# full wöchentlich pgbackrest --stanza=certvia --type=full backup +# diff/inc täglich pgbackrest --stanza=certvia --type=incr backup +``` + +### A.3 Restore / PITR-Prozedur (dokumentierter Ablauf) + +> **Achtung:** Cluster-weit — ersetzt den GESAMTEN Datenbestand aller Mandanten. Für einen +> **einzelnen** Kunden ist der **Portal-Restore** (Schicht B, `/admin/[id]?restore=1`) das +> richtige Werkzeug, nicht PITR. + +```bash +# 1. App + Postgres stoppen (kein Schreibzugriff während des Restore). +docker compose stop app && systemctl stop postgresql # bzw. Coolify-Dienst anhalten + +# 2a. Vollständiger Restore auf den neuesten konsistenten Stand: +pgbackrest --stanza=certvia --delta restore + +# 2b. ODER Point-in-Time-Recovery auf einen Zeitpunkt T: +pgbackrest --stanza=certvia --delta \ + --type=time --target="2026-08-11 14:30:00+02" \ + --target-action=promote restore + +# 3. Postgres starten — spielt WAL bis zum Target und promotet dann. +systemctl start postgresql +# Recovery-Fortschritt in den Postgres-Logs verfolgen (…"recovery stopping before"…). + +# 4. Kohärenz prüfen (s. Restore-Kohärenz unten): Secrets der Zielumgebung müssen +# zu den Daten passen (Pepper/MFA_ENC_KEY), sonst Login/MFA planmäßig zurücksetzen. +# 5. App wieder starten, Smoke-Test (Login, ein Mandant, ein Upload). +``` + +- **Quartalsweiser Restore-Test PFLICHT:** PITR in eine **Wegwerf-Umgebung** wiederherstellen, + Ergebnis protokollieren (der Go-Live fordert das ohnehin für `pgdata`). Ungetestetes Backup = kein Backup. +- **Retention/PITR-Fenster** dem DSB vorlegen (s. Retention-Tabelle unten). + +## MinIO-Objekt-Backup mit restic (vollwertig, Go-Live-Runbook) + +> Ersetzt das frühere „Best-Effort-Key-Kopieren" durch ein **vollwertiges, versioniertes, +> verschlüsseltes** Objekt-Backup. MinIO hält Uploads/Logos **und** die App-Backup-Artefakte +> (`/backups/…`) sowie die DSGVO-Pakete (`/dsgvo-exports/…`); ein +> DB-Backup allein genügt nicht (Backup-Konzept §1/§3). + +```bash +export RESTIC_REPOSITORY=s3:/certvia-restic-prod # eigener Bucket, eigener Zugang +export RESTIC_PASSWORD= # aus Passwortmanager, NIE ins Repo/Bucket +export AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= + +restic snapshots || restic init # einmalig initialisieren +# Zeitplan (Coolify Scheduled Task / cron), täglich: +restic backup /srv/cryptdata/minio --tag minio --host certvia-prod +restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune +restic check --read-data-subset=5% # Integrität stichprobenweise prüfen + +# Restore (ganzes Repo oder gezielt ein Prefix): +restic restore latest --target /srv/cryptdata/minio +restic restore latest --target /tmp/recover --include '/srv/cryptdata/minio//uploads' +``` + +- **Getrennte Buckets/Zugänge:** restic-Repo **nicht** im App-MinIO-Bucket, Schlüssel **nie** + zusammen mit den Artefakten. +- **Konsistenz:** MinIO-Snapshot und DB-Backup laufen zeitnah; die App-Restore-Engine (Schicht B) + stellt DB **und** den Mandanten-Prefix wieder her — beide Ebenen müssen vorhanden sein. + +### Retention je Schicht (dem DSB vorzulegen — Platzhalter, DSB bestätigt) + +| Schicht | Objekt | Vorschlag | +|---|---|---| +| A (pgBackRest) | Voll-Backups | 4 Wochen (`repo1-retention-full=4`) | +| A (pgBackRest) | WAL-Archiv / PITR-Fenster | bis zu 8 Full-Sets (`repo1-retention-archive`) | +| B (App-Export) | Per-Tenant-Snapshots | 30–90 Tage (DSB) | +| DSGVO | Zustellpakete (`dsgvo-exports/`) | Download-Link **1 h TTL**; ZIP kurzlebig, danach löschen | + +### ⚠ Restore-Kohärenz (Vorbedingung im Restore-Runbook) + +> **`PASSWORD_PEPPER`, `MFA_ENC_KEY` und `BACKUP_ENC_KEY` sind Umgebungs-Secrets und stehen +> NICHT im Backup-Artefakt.** Ein Restore in eine Umgebung mit **anderen** Secrets bricht: +> - **anderer `PASSWORD_PEPPER`** → **alle** Passwort-Prüfungen schlagen fehl (kein Login). +> - **anderes `MFA_ENC_KEY`** → TOTP-Secrets nicht entschlüsselbar → MFA-Prüfung bricht. +> - **anderes `BACKUP_ENC_KEY`** → das AES-256-GCM-Artefakt lässt sich gar nicht entschlüsseln. +> +> **Vorbedingung vor jedem Restore:** Zielumgebung hält **exakt die Secrets, mit denen das +> Backup erzeugt wurde**, oder es wird ein **Passwort-/MFA-Reset** (bzw. Neuverschlüsselung) +> eingeplant. Deshalb: Secrets je Umgebung getrennt führen (`docs/SECRETS-REGISTER.md`) und die +> passende Kopie **vor** dem Restore bereitstellen. Cross-Environment-Restore (prod→staging) ist +> nur mit den prod-Secrets **oder** anschließendem Reset lauffähig. + +## Sicherheits-Checkliste Go-Live + +- [ ] Frische, starke Secrets (nicht aus Test übernommen) +- [ ] `RUN_DEMO_SEED` aus, **keine** Demo-Daten in Prod +- [ ] Bootstrap-Admin-Passwort nach erstem Login geändert +- [ ] HTTPS erzwungen, gültiges Zertifikat +- [ ] `pgdata` persistent + Backup + Restore-Test +- [ ] Firewall aktiv, SSH gehärtet +- [ ] Gitea-Repo privat, Zugriff nur für das Team +- [ ] `REDIS_PASSWORD` gesetzt und in `REDIS_URL` eingetragen (F-18) +- [ ] Alle Images auf konkrete Tags gepinnt (kein `:latest`), CI grün (F-11) +- [ ] **Host-Encryption** aktiv: Daten-Volume (`pgdata` + MinIO) auf LUKS/verschlüsseltem Volume, Boot-Unlock-Verfahren dokumentiert (A oder B) +- [ ] **Verschlüsselte Backups**: pgBackRest (`aes-256-cbc`) + `age` + restic eingerichtet, Retention dem DSB vorgelegt, **Restore-Test** dokumentiert +- [ ] **Secrets-Register** (`docs/SECRETS-REGISTER.md`) gepflegt: Ownership + Rotationsregel je Umgebung, Keys nie im Artefakt-Bucket, versiegelte Offline-Kopie +- [ ] **Restore-Kohärenz** geprüft: Zielumgebung hält die zum Backup passenden `PASSWORD_PEPPER`/`MFA_ENC_KEY`/`BACKUP_ENC_KEY` (sonst Reset einplanen) + +--- + +## Supply-Chain & Container-Härtung (F-11 / F-18) + +Diese Maßnahmen sind in `Dockerfile`, `docker-compose*.yml`, `.gitea/workflows/ci.yml` +und `renovate.json` umgesetzt. + +### F-11 — Supply Chain + +- **`npm ci` statt `npm install`** (Lockfile bindend, reproduzierbar). Base-Image ist + **`node:22-slim`** (Debian/glibc) statt Alpine/musl — damit greifen die im Lockfile + hinterlegten glibc-Optional-Deps (lightningcss/oxide/argon2/sharp) zuverlässig. +- **npm 11 im Build gepinnt.** Das committete `package-lock.json` wurde mit npm 11 + erzeugt; das in `node:22.14.0` gebündelte npm 10.9.2 löst `next@16.2.12 → @swc/helpers` + anders auf und würde `npm ci` mit *„out of sync"* abbrechen. `RUN npm i -g npm@11.19.0` + stellt den Resolver-Gleichstand her — **ohne** Lockfile-Änderung. + > **Offene Folgeänderung (Dependency-Lane / F-12):** Sauberer wäre, das Lockfile mit + > npm 10 neu zu erzeugen (`rm -rf node_modules package-lock.json && npm install` unter + > Node 22), damit die npm-Pinnung entfallen kann. Das ist eine `package-lock.json`-Änderung + > und gehört **nicht** in diese Infra-Lane. +- **Image-Pins** (keine rollenden Tags): + `node:22.14.0-slim`, `pgvector/pgvector:0.8.0-pg16`, `redis:7.4.2-alpine`, + `minio/minio:RELEASE.2025-04-22T22-12-26Z`, `mailhog/mailhog:v1.0.1`. +- **Schlanke `migrate`-Stage** statt `builder` für den Migrations-/Seed-Job: kein + `next build`, kein Build-Cache. Sie enthält weiterhin devDeps (tsx/Prisma-CLI) + `src`, + weil `prisma/seed.ts` und `scripts/bootstrap-admin.ts` aus `../src`/`@/server` importieren. + Ein reiner Prisma-CLI-Container würde diese Jobs brechen — die Entkopplung von Seed/Bootstrap + vom App-Code ist als App-seitige Folgeänderung empfohlen. + +### SBOM + +Zwei Wege (der CI-Weg ist optional/nicht-blockierend hinterlegt): + +```bash +# a) aus dem npm-Baum (CycloneDX) — braucht ein valides Lockfile (s. F-12-Hinweis): +npm ci --include=optional && npm sbom --sbom-format cyclonedx --omit dev > sbom.cyclonedx.json + +# b) aus dem gebauten Image (unabhängig vom npm-Baum), z. B. mit Syft: +docker build -t isms:sbom . +syft isms:sbom -o cyclonedx-json > sbom.image.cyclonedx.json +``` + +### F-18 — Härtung & Netzsegmentierung + +- **Redis mit `requirepass`** (`REDIS_PASSWORD`, in `REDIS_URL` eingesetzt). +- **Internes Netz** (`internal: true`) für `postgres`/`redis`/`minio`/`migrate` — kein + Egress, kein Host-Exposure; nur `app` zusätzlich im default-Netz (Coolify-Proxy). +- **`security_opt: no-new-privileges`, `cap_drop: [ALL]`** (gezielte `cap_add` nur für die + Entrypoints von postgres/redis, die intern per gosu den Benutzer wechseln), sowie + **`deploy.resources.limits`** (CPU/RAM) je Dienst. +- **Dev-Compose**: Host-Ports nur noch auf `127.0.0.1` gebunden (Postgres/Redis/MinIO/Mailhog). + +### CI & Renovate + +- **CI**: `.gitea/workflows/ci.yml` (Spiegel `.github/workflows/ci.yml`) fährt + `npm ci → tsc --noEmit → lint → build`, dazu ein **`npm audit`-Gate** + (`--omit=dev --audit-level=high`, hart) plus einen informativen Volllauf. + > **Braucht einen aktivierten Gitea-Actions-Runner** — ohne registrierten Runner läuft + > die Pipeline nicht an. +- **Renovate** (`renovate.json`): wöchentliche, gruppierte Updates; Sicherheits-/OSV-Alerts + sofort und priorisiert. **`next-auth`/`@auth/core` (Beta 5.x)** sind bewusst auf + manuelles Review gesetzt (kein Auto-Merge) — Auth-Regressionen können „fail open" bedeuten (F-01). + +### IM-D — E-Mail-Eingang für Vorfälle (Inbound / E-Mail-to-Ticket) + +Vorfälle können per E-Mail gemeldet werden. Kunden leiten Meldungen an eine +kundenindividuelle **Intake-Adresse** `vorfall-@in.certvia.de` weiter; der +`incident-inbound-worker` holt die Mails per IMAP ab und legt daraus Vorfälle an +(bzw. reiht unklare Mails in die Betreiber-Review). Der Token trägt die +Mandantenzuordnung (global eindeutig, nicht erratbar) — es gibt **kein Postfach je +Kunde**, sondern ein Catch-all. + +**Globaler Setup (einmalig, DNS + Postfach):** + +1. **Subdomain `in.certvia.de`** anlegen und als Mail-Domain einrichten. +2. **Catch-all-Postfach** für `*@in.certvia.de` → ein einzelnes IMAP-Postfach + (alle `vorfall-@…` landen darin). MX-Record auf den Mailhost setzen. +3. **DKIM/SPF/DMARC** für `in.certvia.de` veröffentlichen (Empfang; die + Absender-Authentizität der weitergeleiteten Kundenmails wird über deren DKIM + + die pro Kunde gepflegte Absender-Allowlist geprüft — SPF bricht bei Weiterleitung + und ist bewusst nur ein Signal). +4. **IMAP-Zugang** des Catch-all-Postfachs als Secrets hinterlegen (siehe unten). + +**Env (Dienst `incident-inbound-worker` in `docker-compose.coolify.yml`):** + +| Variable | Zweck | +| --- | --- | +| `INCIDENT_IMAP_HOST` / `INCIDENT_IMAP_PORT` | IMAP-Server des Catch-all-Postfachs (Default-Port 993) | +| `INCIDENT_IMAP_USER` / `INCIDENT_IMAP_PASSWORD` | Zugangsdaten des Catch-all-Postfachs | +| `INCIDENT_IMAP_TLS` | `true` (Default) für IMAPS; `false` nur für STARTTLS/Plain | +| `INCIDENT_IMAP_MAILBOX` | Postfach/Ordner (Default `INBOX`) | +| `INCIDENT_IMAP_POLL_MS` | Abholintervall in ms (Default 60000, min. 15000) | +| `INCIDENT_INTAKE_DOMAIN` | Muss zur Catch-all-Subdomain passen (Default `in.certvia.de`) | + +Ohne `INCIDENT_IMAP_*` beendet sich der Worker **sauber** mit einer Meldung +(kein Crash) — der übrige Betrieb ist davon unberührt. Verarbeitete Mails werden +als `\Seen` markiert; zusätzlich schützt die **Message-ID-Dedupe** gegen +Doppel-Tickets beim erneuten Abholen. + +**Provisionierung je Kunde (Betreiber-Portal):** Beim Onboarding (oder später) im +Mandanten unter **E-Mail-Eingang** die Absender-Domänen (Allowlist) hinterlegen — +die Intake-Adresse wird automatisch erzeugt und angezeigt. Der Kunde richtet die +Weiterleitung ein; sobald die **erste Test-Mail** als Vorfall ankommt, springt der +Status von *Weiterleitung ausstehend* auf *verifiziert* (manueller Override im +Portal möglich). Offene Verifizierungen und zu prüfende Eingänge (kein/unbekannter +Token, Allowlist-/DKIM-Fehlschlag) listet das Betreiber-Dashboard. diff --git a/docs/DEPLOY-PROD-PREBUILT.md b/docs/DEPLOY-PROD-PREBUILT.md new file mode 100644 index 0000000..8267f06 --- /dev/null +++ b/docs/DEPLOY-PROD-PREBUILT.md @@ -0,0 +1,82 @@ +# Prod-Deploy via vorgebaute Images (Plan B) — Runbook + +> **Warum:** Der direkte Build auf dem Prod-Coolify läuft in den Deployment-Timeout +> (~1 h; Ursache ist Coolifys Build-Pfad — u. a. die ~265-ARG-Injektion, die den +> Layer-Cache bei jedem Deploy bricht → Kaltbau). Lösung: Images **einmal auf einem +> leistungsfähigen Host bauen**, in die Registry pushen, und der Prod-Host **zieht nur**. +> Ergebnis: Prod-Deploy = Pull + Migrate = Minuten statt Stunde. + +## Topologie (Stand 2026-09-10) + +| Rolle | Host | +|---|---| +| **Build-Host** (baut + pusht) | `192.168.1.155` — lokales Coolify (= local-gitea-Host), amd64, Docker | +| **Registry** | **git.certvia.de** (Gitea Container Registry), Namespace `msolarczek` | +| **Prod** (`certvia_prod`, GEFIM live) | **coolify.certvia.de** (eigener Server, ≠ 192.168) | +| Quelle | git.certvia.de/msolarczek/certvia, Branch `main` | + +Beteiligte Dateien im Repo: +- `docker-compose.coolify.prebuilt.yml` — wie `docker-compose.coolify.yml`, aber die App-Services ziehen `${REGISTRY:-git.certvia.de/msolarczek}/certvia-*:${IMAGE_TAG:-main}` statt zu bauen (`postgres`/`redis` unverändert). +- `scripts/build-and-push-images.sh` — baut + pusht die drei Images. + +Service → Image (Dockerfile-Target): +- `app` → **certvia-app** (`runner`) +- `migrate`, `worker`, `backup-worker`, `incident-inbound-worker`, `garage-provision` → **certvia-migrate** (`migrate`) +- `garage` → **certvia-garage** (`garage`) + +## Voraussetzung: Gitea-Token +Token in git.certvia.de → Settings → Applications mit Scopes: +`read:repository` (Klonen) + `read:package` + `write:package` (Image Push/Pull). + +## Ablauf je Release + +### 1. Auf dem Build-Host (192.168.1.155) +```bash +docker login git.certvia.de -u msolarczek # Passwort = Token +git clone https://msolarczek:@git.certvia.de/msolarczek/certvia.git cv-build # oder: cd cv-build && git fetch && git pull +cd cv-build && git checkout main && git pull +ALSO_MAIN=true ./scripts/build-and-push-images.sh # baut+pusht Tag UND :main +``` +> **Wichtig:** `ALSO_MAIN=true` setzen → es wird zusätzlich das bewegliche Tag `:main` +> gepusht. Coolify zieht per Default `:main` (siehe Gotcha IMAGE_TAG unten). + +### 2. Prod-Host (coolify.certvia.de) einmalig am Registry anmelden +```bash +docker login git.certvia.de -u msolarczek # Passwort = Token +``` +(oder in der Coolify-UI unter Settings → Docker Registries hinterlegen). Nur beim +ersten Mal / nach Token-Wechsel nötig. + +### 3. Coolify (certvia_prod, coolify.certvia.de) +- **Configuration → „Docker Compose Location"** = `docker-compose.coolify.prebuilt.yml` (einmalig). +- Env unverändert: `RUN_DEMO_SEED=false`, `BOOTSTRAP_ADMIN=false`. +- **Redeploy.** Log zeigt Pull der `certvia-*:main` → `migrate` (achte auf neue Migration) → `garage`/`garage-provision` → `app` healthy. + +### 4. Nach dem Deploy — Bestandsmandanten-Migrationen der Fachdaten +Nur nötig, wenn eine Änderung Bestandsmandanten betrifft (z. B. der 5×5-Backfill). In +Coolify → certvia_prod → Service `backup-worker`/`worker` → Terminal (oder per SSH +`docker exec`): +```bash +npx tsx scripts/backfill-risk-5x5.ts # idempotent, alle Mandanten +``` + +### 5. Smoke-Test +Login → betroffene Modulseiten prüfen (z. B. `/processes`, `/dependencies`). + +## Gotchas (aus dem ersten Live-Lauf gelernt) + +- **`IMAGE_TAG` wird von Coolify NICHT in die Compose-Interpolation gereicht** → die + Datei fällt auf `:main` zurück. Deshalb `:main` immer mitpushen (`ALSO_MAIN=true`). + SHA-genaues Pinning müsste erst geklärt werden (dann `IMAGE_TAG=` in Coolify-Env). +- **Coolify entfernt die alten Container VOR dem Pull.** Fehlt der Ziel-Tag in der + Registry, schlägt der Pull fehl und **prod ist unten**. Also *immer erst* Images + (inkl. `:main`) pushen, *dann* Redeploy. +- **Klon-403:** Ein reiner Package-Token darf nicht klonen — `read:repository` fehlt. +- **Migration-Drift ungefährlich:** `prisma migrate deploy` läuft auch dann sauber (Exit 0), + wenn die DB eine angewandte Migration hat, die lokal nicht mehr existiert (empirisch geprüft). +- Nach Nutzung Token, der im Klartext (URL/History) auftauchte, **widerrufen**. + +## Rollback +Alten Stand deployen: früheres Image-Tag als `:main` retaggen+pushen (auf dem Build-Host) +und Redeploy — oder Compose-Location zurück auf `docker-compose.coolify.yml` (Host-Build, +langsam) als Notnagel. diff --git a/docs/DEVOPS-INTEGRATION-RUNBOOK.md b/docs/DEVOPS-INTEGRATION-RUNBOOK.md new file mode 100644 index 0000000..9c10cb1 --- /dev/null +++ b/docs/DEVOPS-INTEGRATION-RUNBOOK.md @@ -0,0 +1,119 @@ +# DevOps-Integrations-Runbook — 2-Lane-Entwicklung (Onboarding-Wizard) + +> Zweck: **DevOps übernimmt das Integrieren** der Feature-Branches nach `dev` (Merge, +> Validierung, Doku-Pflege, Push). **Entwickler committen nur auf ihren Feature-Branches** +> und müssen sich um Merge/Konsolidierung nicht mehr kümmern. +> Basis-Doku: `docs/STAND-dev-branch.md` (Single Source of Truth), `docs/HANDOVER-DEV.md`. + +--- + +## 1. Setup (Ist-Zustand) + +- **Zwei Git-Worktrees** desselben Repos, die sich **eine** lokale Postgres-DB teilen: + - `~/Projects/ISMS-Tool` → Integrations-Branch **`dev`** (hier arbeitet DevOps). + - `~/Projects/ISMS-Tool-devB` → Dev-B-Worktree (Feature-Branch). +- **Branch-Modell:** Integrationsbranch **`dev`**; Feature-Branches mit **Bindestrich** + (`dev-a1-wizard-shell`, `dev-b1-tasks-erweiterung`, `dev-b2-regel-engine`, …). + ⚠️ **Nicht** `dev/x` verwenden: Git kann nicht gleichzeitig Branch `dev` **und** `dev/x` + führen (D/F-Konflikt) — deshalb Bindestrich. +- **`main`** ist das spätere Merge-Ziel (hier nicht angefasst). +- **Gitea (Remote)** ist aktuell zeitweise offline → Pushes erst, wenn erreichbar. + Durch das geteilte Repo sehen alle Worktrees ein aktualisiertes `dev` sofort (ohne Push). + +## 2. Verantwortungs-Split (neu) + +| Rolle | macht | macht **nicht** | +|-------|-------|------------------| +| **Entwickler (A/B)** | Feature-Branch, kleine Commits je Story, Rebase auf `dev` **vor** dem Erzeugen einer Migration | Merge nach `dev`, Doku-Pflege, Push | +| **DevOps** | Merge Feature-Branch → `dev`, Validierungs-Gate, `STAND-dev-branch.md` pflegen, Push (wenn Gitea da) | Fachlogik implementieren | + +## 3. Integrations-Ablauf (pro fertigem Feature-Branch) + +```bash +# 0) Im Entwickler-Worktree: sauber & auf dev rebased? +git -C ~/Projects/ISMS-Tool-devB status --porcelain # leer = sauber + +# 1) Ins Integrations-Worktree, auf dev, sauberer Tree +cd ~/Projects/ISMS-Tool +git checkout dev +git status --porcelain # leer = sauber + +# 2) Konfliktvorschau (optional) +git merge-tree $(git merge-base dev ) dev | grep -i "changed in both" || echo "keine Konflikte" + +# 3) Nicht-destruktiv mergen (Entwickler-Branch bleibt unangetastet) +git merge --no-ff -m "Merge : in dev" +``` + +**Konflikte** treten fast nur in den **Naht-Dateien** auf — **additiv** auflösen, nie die +Ergänzungen der anderen Lane löschen: +`prisma/schema.prisma` · `scripts/check-module-guards.ts` · `messages/de.json`/`en.json` · +`seed/isms-vorlagenpaket-v2/variables.schema.json`. + +## 4. Validierungs-Gate (muss komplett grün sein) + +```bash +npx prisma generate \ + && npx prisma migrate status \ + && npx tsc --noEmit \ + && npm run lint \ + && npm run build \ + && python3 seed/isms-vorlagenpaket-v2/_verify.py # nur nötig, wenn seed/variables geändert +``` +- `migrate status` muss **„Database schema is up to date!"** melden (sonst → §6). +- `build` führt den **Modul-Guard-Vollständigkeitscheck** als `prebuild` aus. + +## 5. Doku + Branch-Sync + Push + +```bash +# STAND aktualisieren (Executive-Summary-Lane-Zeilen, Migrations-Liste, Commit-Übersicht) +$EDITOR docs/STAND-dev-branch.md +git add docs/STAND-dev-branch.md +git commit -m "Doku: STAND — integriert" + +# Aktive Feature-Branch-Zeiger auf dev nachziehen (optional, Komfort) +git branch -f dev-a1-wizard-shell dev + +# Push NUR wenn Gitea erreichbar: +git fetch # prüfen, ob origin/dev jemand vorausgezogen hat +git push origin dev # bei Divergenz NICHT force-pushen — abstimmen +``` +Commit-Konvention: deutsch, granular, Trailer `Co-Authored-By: Claude Opus 4.8 `. + +## 6. Bekannte Stolpersteine (durch die geteilte DB) + +- **Migrations-Timestamp-Diskrepanz nach Rebase:** Wird eine Migration im Branch neu erzeugt + (neuer Timestamp) und die geteilte DB hat noch die alte angewandt, meldet `migrate status` + „applied ≠ lokal". **Fix ohne Datenverlust** (kein SQL läuft neu): + ```bash + # stalen DB-Eintrag entfernen … + npx prisma db execute --schema prisma/schema.prisma --stdin <<< \ + "DELETE FROM \"_prisma_migrations\" WHERE migration_name='_';" + # … und die committete Migration als angewandt markieren + npx prisma migrate resolve --applied _ + ``` +- **`migrate diff --from-config-datasource` zeigt Fremd-Änderungen:** Da beide Lanes dieselbe + DB teilen, will der Diff die Spalten/Objekte der **anderen** Lane droppen. Beim Erzeugen einer + Migration nur die **eigenen** DDL-Blöcke übernehmen (Entwickler-Aufgabe; DevOps sollte es kennen). +- **Neue RBAC-Rechte/Rollen wirken erst nach DB-Grant:** Permissions werden beim **Login** aus der + DB aufgelöst. Neue Einträge in `ROLE_DEFS` brauchen für **bestehende** Mandanten einen Grant + (Re-Seed/Re-Provisioning oder gezieltes SQL). Neue Mandanten bekommen sie automatisch. +- **Veraltetes JWT nach Re-Seed:** Nach einem Re-Seed zeigen offene Sessions auf alte User-IDs → + Screen „Konto deaktiviert". **Fix:** ab-/neu anmelden (`/api/auth/signout`) — das JWT wird neu aufgelöst. +- **Turbopack-Cache:** Nach Rewrites von Server-Actions kann die Browser-Konsole veraltete + HMR-Fehler zeigen. Maßgeblich sind `tsc`/`build` + `preview_logs` (Server) — bei Zweifel Dev-Server neu starten. + +## 7. Nicht-destruktive Regeln + +- Feature-Branches **in `dev` mergen** (`--no-ff`) — **nie** die Entwickler-Branches rebasen/umschreiben. +- Einen in einem Worktree ausgecheckten Branch **nicht** löschen. +- Vollständig gemergte Branches (z. B. `dev-b1`, sobald `dev-b2` gelandet ist) dürfen aufgeräumt + (gelöscht) werden — nur wenn nicht ausgecheckt. +- Bei `origin/dev`-Divergenz **kein** `--force` — abstimmen und mergen. + +## 8. Aktueller Stand (zum Zeitpunkt der Runbook-Erstellung) + +- `dev` enthält beide Lanes bis: **A1-1, F2, A1-2** (Dev A) und **F1, B1, F4** (Dev B), konsolidiert. +- Feature-Branches: `dev-a1-wizard-shell` (= `dev`), `dev-b2-regel-engine` (Dev B, offene Stories). +- Offene Stories: A2 (Scoping + AL zentral), A3, F3+B2 (Regel-Engine), B3 (Fragebogen), B4 (Richtlinien). +- Migrationen auf `dev`: siehe `docs/STAND-dev-branch.md` (Liste + Reihenfolge). diff --git a/docs/FEINDESIGN-framework-assessment.md b/docs/FEINDESIGN-framework-assessment.md new file mode 100644 index 0000000..3c99f18 --- /dev/null +++ b/docs/FEINDESIGN-framework-assessment.md @@ -0,0 +1,290 @@ +# Feindesign B1 — Assessment und Readiness für zwei Frameworks + +**Stand:** 2026-08-27 · **Branch:** `feature/iso27001-framework-mapping` · **Status:** Entwurf zur Abnahme + +> **Ausgangslage:** AP1–AP5 sind umgesetzt. Ein ISO-Mandant hat Dokumente, SoA-Modell, Kennzahlen, +> Managementbewertung und Korrekturmaßnahmen. Was fehlt, ist die **Bewertungs- und Readiness-Sicht**: +> `maturity.ts`, `scope-filter.ts`, `assessment-level.ts` und `readiness.ts` kennen kein Framework und +> rechnen durchgängig VDA ISA — AL2/AL3, Prüfziele, Reifegrad 0–3, MUSS/SOLL. +> +> **Belegter Bruch:** `soa-context.ts:151` und `export-context.ts:49` lesen `controlAssessment`. +> **Keine einzige Stelle liest `soaEntry`.** Das in AP3 gebaute SoA-Modul ist von der Auswertung +> abgekoppelt — die Daten liegen da, die Readiness greift nicht darauf zu. + +Grundlage: `docs/KONZEPT-framework-iso27001.md` (Lane 3), `docs/FRAMEWORK-MAPPING-ISO27001.md`, +`docs/UEBERGABE-framework-iso27001.md`. + +--- + +## 1. Leitentscheidung: die Belegbasis liegt **unterhalb** der Framework-Strategie + +Es werden **nicht zwei Engines** gebaut. Der Belegstatus eines Controls — ist die zuständige Richtlinie +freigegeben, existiert das Verfahren, hängt ein Asset dran, gibt es einen Wirksamkeitsnachweis — ist +eine **Tatsache über die Organisation**, keine Frage der Norm. Ob R08 freigegeben ist, ändert sich +nicht dadurch, ob ISO oder VDA ISA danach fragt. + +Würde man die Belegbasis mitparallelisieren, entstünden zwei Bewertungen derselben Realität, die +auseinanderlaufen können. Im Audit steht dann „Berechtigungsvergabe: TISAX Reifegrad 3" neben +„ISO: teilweise umgesetzt" — ein Widerspruch über denselben Sachverhalt. + +**Regel: eine Belegbasis, zwei Bewertungen.** + +``` +Schicht 3 Sichten /soa · /audit-readiness · Exporte · Wizard-Schritte → Reiter je Framework +Schicht 2 Strategie Scope · Zielwert · Bewertung · Vokabular → je Framework +Schicht 1 Belegbasis loadEvidenceResolver → ControlEvidence → GETEILT +Schicht 0 Fachdaten PolicyDocument · Evidence · Asset · Risk · Measure → GETEILT +``` + +Das ist derselbe Schnitt wie bei den Richtlinien: ein Umsetzungstext, zwei Anforderungssichten. + +--- + +## 2. Was generalisiert wird (Schicht 1) + +`ControlEvidence` (`src/lib/maturity.ts:54`) ist bereits **framework-neutral** — Richtlinienstatus, +Verfahrensstatus, Asset-/Risiko-Verknüpfung, operativer Wirksamkeitsnachweis. Nur der *Eingabetyp* des +Resolvers ist TISAX-spezifisch. + +**Änderung:** `C5ControlSpec` (`maturity.ts:16`) wird auf ein neutrales `ControlSpec` reduziert: + +```ts +export interface ControlSpec { + control: string; // "4.1.2" | "A.8.5" + title: string; + policy: string[]; // ["R08"] + verfahren: string[]; // ["VA-03"] + needsAsset: boolean; + needsRisk: boolean; +} +// C5ControlSpec extends ControlSpec { target: number } — TISAX-Zusatzfeld bleibt dort +``` + +`loadEvidenceResolver(db, completeControls)` nimmt künftig `ControlSpec`. **Für TISAX ändert sich +nichts** — `C5ControlSpec` erfüllt das Interface. + +### ISO-Specs kommen aus dem Mapping, nicht von Hand + +`mapping-iso.json` trägt je Anforderung bereits `policy` (R-Code) und `verfahren` (VA-Codes). Daraus +lässt sich der ISO-`ControlSpec` erzeugen. `needsAsset`/`needsRisk` werden über den vorhandenen +Crosswalk `ISO_TO_ISA` (`src/lib/iso-isa-crosswalk.ts`, 87 der 120) vom ISA-Spec **geerbt**; für die +33 ISO-eigenen Abschnitte werden sie explizit gesetzt — sinnvoll nur bei A.5.9 (`needsAsset`) sowie +6.1.2/6.1.3/8.2/8.3 (`needsRisk`). + +**Umsetzung:** `_generate_iso.py` erzeugt zusätzlich `src/lib/control-specs-iso.ts` — analog zu +`control-titles-iso.ts` und `iso-isa-crosswalk.ts`. Damit bleibt das Mapping die einzige Quelle und +niemand pflegt eine zweite Liste. + +--- + +## 3. Die Strategie-Schnittstelle (Schicht 2) + +```ts +export type FrameworkKey = "TISAX" | "ISO_27001"; + +/** Bewertung eines Controls — je Framework ein eigener Typ, nie gemischt. */ +export type Verdict = + | { kind: "maturity"; suggested: 0 | 1 | 2 | 3; confirmed: number | null; target: 2 | 3 } + | { kind: "status"; applicable: boolean; suggested: ImplStatus; confirmed: ImplStatus | null }; + +export type ImplStatus = "umgesetzt" | "teilweise" | "geplant"; + +export interface AssessmentRow { + control: string; + title: string; + spec: ControlSpec; + evidence: ControlEvidence; // aus Schicht 1, identisch für beide Frameworks + verdict: Verdict; // je Framework interpretiert + gaps: OpenPoint[]; +} + +export interface FrameworkStrategy { + key: FrameworkKey; + /** Anzeigename für Reiter und Berichte. */ + label: string; // "TISAX / VDA ISA 2027" | "ISO/IEC 27001:2022" + /** Datei im Vorlagenpaket. */ + mappingFile: string; // "mapping.json" | "mapping-iso.json" + /** Controls im Geltungsbereich — TISAX: AL + Prüfziele · ISO: Anwendbarkeit aus der SoA. */ + controlsInScope(db: TenantDb): Promise; + /** Bewertung eines Controls aus geteiltem Beleg + framework-eigener Regel. */ + evaluate(spec: ControlSpec, ev: ControlEvidence, ctx: EvalContext): Verdict; + /** Offene Punkte, die aus der Lücke zum Zielwert folgen. */ + gaps(spec: ControlSpec, ev: ControlEvidence, v: Verdict): OpenPoint[]; + /** Kennzahl und Textband — framework-eigenes Vokabular, kein gemeinsamer Nenner. */ + summarise(rows: AssessmentRow[]): ReadinessSummary; +} +``` + +`buildControlRows` (`soa-context.ts:146`) wird zu `buildAssessment(db, tenantId, framework)` und +delegiert an die Strategie. Die Belegauflösung bleibt, wo sie ist. + +### TisaxStrategy — verhaltensgleich extrahieren + +Reine Umverdrahtung, **kein** neues Verhalten: `loadScopeInput` + `controlsInScope` → `controlsInScope`, +`suggestMaturity` + `targetMaturity` → `evaluate`, `openPoints` → `gaps`, `computeReadiness` → +`summarise`. Regressionsschutz: Snapshot-Test gegen die heutige Ausgabe (siehe §7). + +### IsoStrategy — neu + +| Aspekt | Regel | +|---|---| +| **Scope** | `SoaEntry.applicable = true`. Kein AL, keine Prüfziele. Klauseln 4–10 sind **immer** im Scope (nicht Gegenstand der Anwendbarkeit). | +| **Zielwert** | `implementationStatus = "umgesetzt"` für jedes anwendbare Control. Keine Stufung. | +| **Vorschlag** | aus `ControlEvidence`: Richtlinie *und* Verfahren `validiert` + geforderte Verknüpfungen vorhanden → `umgesetzt`; teilweise belegt → `teilweise`; sonst `geplant`. | +| **Bestätigung** | `SoaEntry.implementationStatus` ist der bestätigte Wert; der Vorschlag überschreibt ihn nie (Muster wie `ControlAssessment.suggested` / `confirmedValue`). | +| **Lücken** | fehlende Begründung, fehlender Nachweis, Status ≠ „umgesetzt" bei anwendbarem Control. | + +--- + +## 4. Vorbelegung bei Doppel-Framework — gegen Doppelerfassung + +Führt ein Mandant beide Normen, darf der ISB **nicht zweimal dasselbe beantworten**. Über +`ISO_TO_ISA` ist bekannt, welches ISA-Control denselben Bibliotheksabschnitt trägt. + +**Regel:** Ist das zugehörige ISA-Control bestätigt und erreicht seinen Zielreifegrad, schlägt die +ISO-Sicht `umgesetzt` vor — mit Verweis auf denselben Nachweis. Der ISB **bestätigt**, das System +setzt nichts automatisch. + +Für die 33 ISO-Anforderungen ohne ISA-Gegenstück (Managementsystem-Klauseln, Clear Desk, DLP, +Kapazität, Zeitsynchronisation …) gibt es keine Vorbelegung — sie werden regulär bewertet. Das ist +zugleich die ehrliche Aussage an den Kunden: **das ist die Delta-Arbeit, die ISO gegenüber TISAX +zusätzlich verlangt.** Diese Liste ist ein verkaufbares Ergebnis für sich. + +--- + +## 5. Sichten und Reiter (Schicht 3) + +| Bereich | Reiter ISO / TISAX | Begründung | +|---|:--:|---| +| Controls- / SoA-Sicht (`/soa`) | **ja** | zwei Kataloge, zwei Zielsysteme | +| Readiness (`/audit-readiness`) | **ja** | je Norm eine eigene Aussage und ein eigenes Vokabular | +| Exporte | **ja** | VDA-ISA-Export bleibt TISAX; SoA und Annex-A-Gap sind ISO | +| Richtlinien (`/policies`) | **nein** | ein Dokumentensatz; Parallelanzeige im Dokument ist gebaut | +| Nachweise | **nein** | ein Beleg belegt eine Tatsache, unabhängig von der fragenden Norm | +| Assets, Risiken, Vorfälle, Lieferanten, Aufgaben | **nein** | framework-neutral | + +**Reiter-Verhalten:** ein aktives Framework → kein Reiter, direkte Anzeige. Zwei aktive Frameworks → +Reiter, Vorauswahl `TenantFramework.isPrimary`. Die Auswahl gehört in die URL (`?fw=iso`), damit +Deep-Links und Berichte reproduzierbar sind. + +**Harte Regel: keine gemischte Gesamtzahl.** Ein „Erfüllungsgrad 87 %" über beide Normen ist fachlich +sinnlos — ein Reifegrad 0–3 und ein Umsetzungsstatus lassen sich nicht mitteln. Je Norm eine Kennzahl, +immer getrennt ausgewiesen. + +--- + +## 6. Vokabular + +`REIFEGRAD_BANDS` (`readiness.ts:16`) ist TISAX-Sprache („Assessment-reif", „AL-Ziel"). Für ISO +gehören eigene Bänder auf Basis des Umsetzungsgrads — Vorschlag: + +| Anteil „umgesetzt" | Band | Aussage | +|---|---|---| +| < 50 % | Aufbau | wesentliche Maßnahmen noch offen | +| 50–79 % | In Umsetzung | Struktur steht, Nachweise fehlen | +| 80–99 % | Zertifizierungsnah | wenige offene Punkte, Wirksamkeitsnachweise ergänzen | +| 100 % | Zertifizierungsreif | alle anwendbaren Controls umgesetzt und belegt | + +**Ein ISO-Auditbericht darf nicht mit „Reifegrad 2,4" argumentieren.** Der Nachweis lautet +„umgesetzt, hier ist der Beleg". Der Reifegrad bleibt unter ISO ein optionales Beratungsinstrument — +sichtbar als Zusatzspalte, nie als Erfüllungsaussage (Entscheidung aus dem Fachgespräch, Variante 3). + +--- + +## 7. Regressionsschutz + +Die Extraktion der `TisaxStrategy` ist der riskanteste Teil. Absicherung **vor** dem Umbau: + +1. **Snapshot erzeugen:** `buildControlRows` für den Demo-Mandanten (321 Anforderungen, 45 Controls) + als JSON festhalten — Reifegradvorschlag, Zielwert, Belegstatus und offene Punkte je Control. +2. **Nach dem Umbau vergleichen:** `buildAssessment(db, tenantId, "TISAX")` muss denselben Snapshot + liefern. Abweichung = Regression, kein „ist besser geworden". +3. Als `scripts/test-framework-assessment.ts` in der Hausform der übrigen `test-*.ts` ablegen. + +Ergänzend unverändert gültig: `_verify.py`, `_verify_iso.py --lang de|en`, `_render_diff.py HEAD`, +`test-framework-dryrun.ts`. + +--- + +## 7a. Priorisierung nach Kundenlage (Nachtrag 2026-08-27) + +**Ist-Lage:** Die Mehrzahl der Mandanten führt TISAX, **ein** Mandant ISO, **keiner beide**. + +Daraus folgt zweierlei: + +1. **Das Regressionsrisiko dominiert.** Der riskanteste Teil ist nicht die ISO-Logik, sondern die + verhaltensgleiche Extraktion der `TisaxStrategy` — sie betrifft alle Bestandsmandanten. Schritt 1 + (Snapshot) ist damit nicht Kür, sondern die wichtigste Einzelmaßnahme des ganzen Pakets. +2. **Zwei Themen lassen sich zurückstellen** — beide betreffen ausschließlich den Doppel-Mandanten, + den es heute nicht gibt: + +| Zurückgestellt | Was entfällt vorerst | Wieder aufnehmen, wenn | +|---|---|---| +| **Schritt 7** — Vorbelegung über `ISO_TO_ISA` | Übernahmevorschlag aus dem jeweils anderen Framework | ein Mandant beide Normen führt | +| **Schritt 8b** — Reiter-UI | Umschalter in `/soa` und `/audit-readiness`; bei einem aktiven Framework wird direkt angezeigt | ein Mandant beide Normen führt | + +**Was dabei nicht zurückgestellt werden darf:** die **Strategie-Schnittstelle** und der +**Framework-Parameter** in `buildAssessment`. Beide kosten jetzt fast nichts und sind später teuer +nachzurüsten, weil sonst 7 Aufrufstellen erneut angefasst werden müssen. Die Architektur bleibt +zweigleisig, nur die Oberfläche zeigt vorerst ein Gleis. + +Erwartete Wirkung auf den Aufwand: **5–8 PT → 4–6 PT.** + +--- + +## 8. Arbeitsschritte + +| # | Schritt | Ergebnis | +|---|---|---| +| **1** | Snapshot-Test der heutigen TISAX-Ausgabe | Regressionsnetz steht, **vor** jedem Umbau | +| **2** | `ControlSpec` einführen, `loadEvidenceResolver` darauf umstellen | Belegbasis framework-neutral, TISAX unverändert | +| **3** | `_generate_iso.py` erzeugt `control-specs-iso.ts` | ISO-Specs aus dem Mapping, keine Zweitpflege | +| **4** | `FrameworkStrategy` + `TisaxStrategy` (reine Extraktion) | Snapshot grün | +| **5** | `IsoStrategy` (Scope aus SoA, Status statt Reifegrad) | ISO-Bewertung rechnet | +| **6** | `buildAssessment(db, tenantId, framework)` ersetzt `buildControlRows` | 7 Dateien rufen es direkt, 13 hängen an der Assessment-Logik insgesamt | +| ~~**7**~~ | ~~Vorbelegung über `ISO_TO_ISA`~~ | **zurückgestellt** — betrifft nur Doppel-Mandanten (§7a) | +| **8a** | ISO-Readiness-Bänder und framework-richtige Beschriftung | ISO-Mandant sieht ISO-Vokabular | +| ~~**8b**~~ | ~~Reiter in `/soa` und `/audit-readiness`~~ | **zurückgestellt** (§7a) | +| **9** | ISO-Exporte: SoA + Annex-A-Gap | Managementbewertung hat ihre Eingabe | + +Schritte 1–4 sind Pflicht und hängen aneinander. 5–9 sind danach teilbar. + +--- + +## 9. Definition of Done + +| Prüfung | Erwartung | +|---|---| +| Snapshot-Test TISAX | 0 Abweichungen zur Ausgabe vor dem Umbau | +| Reiner ISO-Mandant | Readiness und SoA rechnen; keine AL-, Prüfziel- oder Reifegrad-Begriffe in der Oberfläche | +| Reiner TISAX-Mandant | Verhalten und Beschriftung unverändert | +| Doppel-Mandant | *zurückgestellt* — Architektur trägt es, Oberfläche zeigt es noch nicht (§7a) | + +| ISO-Delta | die 33 Anforderungen ohne ISA-Gegenstück sind als eigene Liste ausweisbar | +| Gate | `tsc`, `lint`, `build`, `_verify*`, `_render_diff`, beide Testskripte grün | + +--- + +## 10. Aufwand und Risiken + +**Aufwand:** 4–6 PT im vorgezogenen Umfang (§7a), 5–8 PT vollständig. Schwerpunkt liegt auf Schritt 4 (verhaltensgleiche Extraktion) und Schritt 8 +(zwei Sichten statt einer), nicht auf der ISO-Logik selbst — die ist schlank. + +| Risiko | Gegenmaßnahme | +|---|---| +| TISAX-Regression bei der Extraktion | Snapshot-Test **vor** Schritt 2 anlegen, als Merge-Gate setzen | +| Belegbasis wandert versehentlich in die Strategie | Review-Kriterium: `loadEvidenceResolver` darf `FrameworkKey` nicht kennen | +| Gemischte Kennzahlen schleichen sich in die UI | `ReadinessSummary` je Framework typisieren, keine Aggregation über beide | +| ISO-Scope hängt an gepflegter SoA | leere SoA → Readiness meldet „Anwendbarkeit noch nicht erklärt" statt 0 % | +| Doppelte Datenpflege beim Doppel-Mandanten | Schritt 7 ist nicht optional | + +--- + +## 11. Was ausdrücklich **nicht** gebaut wird + +- Kein Reiter über Richtlinien, Nachweisen, Assets, Risiken oder Aufgaben. +- Keine gemeinsame Kennzahl über beide Frameworks. +- Kein Reifegrad als ISO-Erfüllungsaussage (optionale Zusatzspalte ja, Bewertungsgrundlage nein). +- Keine Änderung an der VDA-ISA-Logik über die reine Extraktion hinaus. +- Kein Umbau von `readiness.ts`/`gap-consolidation.ts` — die Rechen-Engines sind numerisch + standard-agnostisch und werden von beiden Strategien gefüttert. diff --git a/docs/FEINDESIGN-identity-mandanten.md b/docs/FEINDESIGN-identity-mandanten.md new file mode 100644 index 0000000..e8a33d7 --- /dev/null +++ b/docs/FEINDESIGN-identity-mandanten.md @@ -0,0 +1,219 @@ +# Feindesign & Implementierungsplan — Zentrale Identität + Mandanten-Mitgliedschaften (certvia) + +> Produkt: **certvia** (ISMS-Tool). Grundlage: [KONZEPT-identity-mandanten.md](KONZEPT-identity-mandanten.md) (Option C, Entscheidungen A–E + Two-Step-Login + Passphrasen). Dieses Dokument ist der **umsetzbare Bauplan** für ein mehrköpfiges, noch zu onboardendes Entwicklerteam inkl. PM. Alle Datei:Zeile-Angaben beziehen sich auf Branch `dev`. + +## 0. Wie dieses Dokument zu lesen ist +- **PM:** §7 (Meilensteine), §8 (Risiken), §9 (DoD), §11 (Rollen/Cadence), §12 (Aufwand). +- **Entwickler:** §1–§6 (Feindesign), §10 (Onboarding + „Goldene Regeln"). +- **Alle:** §1 ist die eine Leitentscheidung, aus der alles Weitere folgt. + +--- + +## 1. Leitentscheidung (das Sicherheitsnetz): `User.id` bleibt stabil +Wir führen **nicht** eine große Umverkabelung durch. Stattdessen: +- **`User` bleibt** die per-Mandant-Zeile (jetzt gedanklich „Mitgliedschaft") mit **derselben `id`** und **derselben `tenantId`**. +- Wir **schneiden nur die Auth-Felder heraus** in eine neue globale **`Identity`** und hängen `User.identityId → Identity.id` an. +- In der Session bleibt **`session.user.tenantId`** erhalten — es zeigt künftig auf den **aktiven** Mandanten. Dadurch bleiben **~356 `dbForTenant(session.user.tenantId)`-Stellen, alle 6 Owner-FKs (`assets/processes/risks/measures.owner_id`, `user_roles`, `webauthn`) und das RLS-Modell unangetastet.** + +**Folge:** Der Umbau konzentriert sich auf **Login, Session-Aufbau, Mandantenauswahl, Nutzer-Lifecycle** — nicht auf die 356 Fachstellen. Das ist die risikoärmste Schneise. + +> **Zusatz-Vereinfachung (Entscheidung D):** Es gibt **keinen Produktivdatenbestand** (nur Testdaten). Deshalb **kein Backfill/Merge**, sondern **Schema-Neuschnitt + Reseed**. Der aufwändigste und riskanteste Teil eines solchen Umbaus entfällt komplett. + +--- + +## 2. Zieldatenmodell (konkret) + +**Neu — `Identity` (global, KEIN `tenantId`, NICHT in `TENANT_MODELS`):** +`id, email @unique, passwordHash, mustChangePassword, mfaSecret, mfaEnrolledAt, recoveryCodes, lastTotpStep, failedLogins, lockedUntil, sessionsValidAfter, status, createdAt, updatedAt`. +→ Übernimmt exakt die Felder, die heute in `User` (`schema.prisma:98-139`) und `PlatformAdmin` doppelt liegen. + +**Geändert — `User` = Mitgliedschaft (bleibt in `TENANT_MODELS`, behält `tenantId`+`id`):** +- **entfernt** (wandern zu Identity): `passwordHash, mfaSecret, mfaEnrolledAt, recoveryCodes, lastTotpStep, failedLogins, lockedUntil, mustChangePassword, sessionsValidAfter, isPlatformAdmin`. +- **neu:** `identityId → Identity`. +- **bleibt:** `tenantId, name, status: UserStatus, userRoles`, alle Ownership-Relationen. `@@unique([tenantId, email])` → ersetzt durch `@@unique([tenantId, identityId])` (eine Person max. 1 Mitgliedschaft je Mandant); `email` bleibt als Denormalisierung optional oder entfällt (Quelle = Identity). + +**`WebAuthnCredential`** (`schema.prisma:143-160`): `userId → identityId`, `tenantId` entfällt → **raus aus `TENANT_MODELS`**, RLS-Policy der Tabelle entfernen (Passkeys sind identitäts-, nicht mandantengebunden). + +**`AuthToken`** (`schema.prisma:1679-1700`): `principalType/principalId` → auf `identity` umstellen; neuer `TokenType: "invitation"` (heute wird `password_reset` mit 7-Tage-TTL zweckentfremdet). + +**`PlatformAdmin`** (`schema.prisma:211-234`): **bleibt getrennt** (Entscheidung E). *Option (empfohlen, klein):* eine Identity kann zusätzlich Plattform-Admin sein → `PlatformAdmin.identityId` als Verweis, Store aber getrennt. Nicht zwingend für Phase 1. + +**`TENANT_MODELS` (`db.ts:81-148`):** `Identity` **nicht** aufnehmen (globaler Lookup über Owner-`prisma`, wie heute der Login). `WebAuthnCredential` **entfernen**. `User` **bleibt** drin. + +--- + +## 3. Session-/Token-Shape (neu) + +**JWT/Session (`next-auth.d.ts` erweitern):** +``` +identityId +activeTenantId → gespiegelt als session.user.tenantId (⇒ 356 Call-Sites unverändert!) +activeMembershipId (= User.id des aktiven Mandanten) +memberships[] [{ tenantId, tenantSlug, membershipId, tenantName }] (schlanke Liste für den Switcher) +permissions[] (des AKTIVEN Mandanten) +tenantSlug (des aktiven Mandanten) +isPlatformAdmin, mfaEnrolled, tokenIssuedAt +``` + +**Kritische Regel:** `session.user.tenantId === activeTenantId`, immer **genau ein** aktiver Mandant. Kippt das (leer/mehrdeutig), kippt der RLS-Kontext → Fail-closed. + +**Konsumenten anpassen (aber minimal):** +- `auth.ts` jwt/session-Callbacks (`:276-299`): neue Felder setzen, `tenantId` = aktiver Mandant. +- `action-guard.ts:29-84` und `(app)/layout.tsx:37-120`: `sessionsValidAfter` künftig aus **Identity** lesen; Permissions bei **Mandantenwechsel** neu auflösen (heute beim Login eingefroren). +- `rbac.ts` (`hasPermission/requirePermission`, 43 Konsumenten): unverändert — liest weiter `session.user.permissions`, die aber pro aktivem Mandant befüllt werden. +- `proxy.ts`: neuer Pfad `/select-tenant` in Post-Login-Gate; „angemeldet, aber kein aktiver Mandant → `/select-tenant`". + +--- + +## 4. Die Flows (Feindesign) + +### 4.1 Login (Two-Step, MFA beim Login) — `login/page.tsx`, `auth.ts` +1. **Seite 1: E-Mail + Passwort** (Feld „Organisation" **entfällt**). `signIn` gegen **Identity** (`auth.ts:96` von `user.findMany` auf `identity.findUnique({email})` umstellen; Lockout/Dummy-Verify bleiben). +2. **MFA-pending-Zustand:** kurzlebiger, signierter, einzweckiger Server-State (kein voller Session-Cookie). Realisierung: eigener NextAuth-Step oder ein `mfa_pending`-JWT mit 5 min TTL, das nur `/login/mfa` bedient. +3. **Seite 2: MFA** — angezeigt, wenn Identity MFA hat **oder** ≥ 1 Mitgliedschaft in MFA-Pflicht-Mandant. TOTP/Passkey verifizieren (`mfa.ts:47`, Replay via Identity.`lastTotpStep`) oder Enroll erzwingen. +4. **Volle Session** ausstellen (Identity + MFA erfüllt), `memberships[]` laden. +5. **Weiterleitung:** 1 Mitgliedschaft → direkt `/dashboard` (activeTenant gesetzt); mehrere → `/select-tenant`; keine → Hinweisseite. + +### 4.2 Mandantenauswahl & -Wechsel — neu: `/select-tenant` + Action `setActiveTenant` +- Server Action `setActiveTenant(membershipId)`: **(1)** Membership gehört zur Session-Identity? **(2)** Mitgliedschaft+Mandant ACTIVE? **(3)** `sessionsValidAfter` ok? **(4)** MFA-Netz: verlangt Zielmandant MFA und nicht erfüllt → Enroll. Dann Token neu prägen: `activeTenantId/activeMembershipId/permissions/tenantSlug`. +- **Sicherheitskontrollen (Pflicht):** aktiver `tenantId` **server-autoritativ** (nie Client-Input); Re-Validierung bei jedem Wechsel; **Audit** „Identity → Mandant". (Siehe §8.) +- **Tenant-Switcher** in `(app)/layout.tsx` (Kopf/Sidebar) → ruft `setActiveTenant`. + +### 4.3 Einladung (Standard-Anlageweg) — `auth-selfservice.ts`, `auth-token.ts`, neue Seite `/invite` +- Neuer **`TokenType: "invitation"`** + Zielseite **`/invite?token=`** (Erst-Passwort + optional MFA **auf der Identity** setzen), statt Zweckentfremdung von `/reset`. +- **Neutralität:** Der einladende Admin sieht **immer** „Einladung gesendet" — unabhängig davon, ob die Identity schon existierte (kein Cross-Tenant-Leak). +- Existiert die Identity → Mail „Sie wurden zu Mandant X hinzugefügt" + **Bestätigungslink** (Beitritt annehmen). Existiert nicht → „Konto einrichten + beitreten". + +### 4.4 Nutzeranlage +- **Plattform** (`platform-users.ts:89`): `createTenantUser` → Identity finden/erstellen + Membership + Rollen; **`pwMode "set"` + Fallback-Passwort entfernen**; Betreiber darf direkt verknüpfen. +- **Kunde** (`tenant-users.ts:139`): `createUser` → **immer Einladung**; „Passwort setzen"-Zweig raus. +- **Onboarding-Wizard** (`onboarding-team.ts:166`): `inviteFunctionHolder` → Identity-Einladung statt User+Passwort. +- **UI** (`user-forms.tsx`): pwMode-Auswahl entfällt → reines Einladungsformular (Name, E-Mail, Rollen). + +### 4.5 MFA-Pflicht-Durchsetzung (Mandanten-Policy trifft Identity-MFA) +- Gates umstellen: `(app)/layout.tsx:73-79`, `enroll-mfa/page.tsx:24-32`, `(platform)/layout.tsx:27` → prüfen **Identity.mfaEnrolledAt** statt `User`. +- `mfa-policy.ts:7` (`resolveMfaRequired`, mandantenweit) bleibt. Regel: **strengster betretener Mandant gewinnt**; da MFA an der Identity hängt, deckt eine Einrichtung alle ab. + +### 4.6 Passwort/MFA-Reset → Identity-Ebene, raus aus Mandantenverwaltung +- **Entfernen:** `platform-users.ts:152` (`resetTenantUserPassword`), `tenant-users.ts:207` (`resetUserPassword`) + UI-Bindungen (`admin/[id]/page.tsx:205`, `settings/users/page.tsx:105`). Ersatz: Identity-Self-Service (Recovery-Codes) + Plattform-Ebene. +- **Umleiten auf Identity:** `auth-recovery.ts` (gesamt), `account.ts:66` (`changeOwnPassword`), `sessions.ts:34/92` (`sessionsValidAfter` an Identity), `webauthn.ts:73` (Passkey an Identity), `secret-crypto.ts`-Nutzung unverändert (Schlüssel bleibt). + +--- + +## 5. Migrationsstrategie (DB) +Dank Entscheidung D **kein Backfill**. Ablauf: +1. **Schema-Recut** in `schema.prisma`: `Identity` neu, `User` verschlanken (+`identityId`), `WebAuthnCredential`/`AuthToken` umhängen. +2. **Forward-Migration(en):** `identities` (ohne RLS/Policy!), `users`-Spalten entfernen + `identity_id` FK, `webauthn_credentials` `tenant_id`/Policy entfernen + `identity_id`, `auth_tokens` principal-Umbau. RLS-Policies der betroffenen Tabellen anpassen (analog `rls_enforce`-Muster, `20260730160000`). +3. **`db.ts`:** `TENANT_MODELS` anpassen (Identity raus lassen, WebAuthn entfernen). +4. **Reseed:** `prisma/seed.ts`, `provision.ts`, `bootstrap-admin.ts`, `sync-role-permissions.ts` auf Identity+Membership. Testumgebung frisch aufsetzen. + +> Für die Test-/Coolify-Instanz: einmalig **DB leeren** (nur Testdaten) → `migrate deploy` → Seed. Kein Sonderpfad nötig. + +--- + +## 6. Arbeitspakete (Workstreams) für das Team + +| WS | Inhalt | Kernfiles | Abhängig von | +|---|---|---|---| +| **WS0 Fundament** | `Identity`-Modell, Schema-Recut, Migrationen, `TENANT_MODELS`, RLS-Anpassung WebAuthn | `schema.prisma`, `prisma/migrations/*`, `db.ts` | — (Blocker) | +| **WS1 Auth-Kern** | Login gegen Identity, Two-Step + MFA-pending, Token/Session-Shape, jwt/session-Callbacks | `auth.ts`, `next-auth.d.ts` | WS0 | +| **WS2 Mandantenkontext** | `/select-tenant`, `setActiveTenant`, Tenant-Switcher, Guards + Permissions bei Wechsel, `proxy.ts` | `action-guard.ts`, `(app)/layout.tsx`, `proxy.ts`, `rbac.ts` | WS1 | +| **WS3 Einladungs-Lifecycle** | `invitation`-Token, `/invite`-Seite, Anlage überall auf Einladung, „Passwort setzen" raus | `auth-token.ts`, `auth-selfservice.ts`, `platform-users.ts`, `tenant-users.ts`, `onboarding-team.ts`, `user-forms.tsx` | WS0 | +| **WS4 Passwort/MFA an Identity** | Reset/Change/Email-Change, MFA/Passkey/Recovery, Sessions-Invalidierung, Reset raus aus Mgmt | `auth-recovery.ts`, `account.ts`, `sessions.ts`, `webauthn.ts`, `platform.ts` | WS0 | +| **WS5 UI** | Login-Seiten (2-stufig), `/select-tenant`, Switcher, Einladungsformulare | `login/*`, neue Seiten, `(app)/layout.tsx` | WS1, WS2 | +| **WS6 Seed/Provision/Bootstrap** | Reseed auf Identity, `provision.ts`, `bootstrap-admin.ts`, `sync-role-permissions.ts` | genannte | WS0 | +| **WS7 Tests & Gate** | neue `scripts/test-*`: Identity-Login, Tenant-Switch-Isolation, MFA-Enforcement multi-tenant, Einladung, Two-Step-Bypass | `scripts/test-*.ts` | fortlaufend | + +**Parallelisierung:** Nach **WS0** laufen **WS1, WS3, WS4, WS6** parallel. **WS2** setzt auf WS1, **WS5** auf WS1+WS2. **WS7** durchgehend (jede Story bringt ihren Test mit). + +--- + +## 7. Meilensteine (PM-Sicht) +| M | Ergebnis (Demo-fähig) | umfasst | +|---|---|---| +| **M0** | Onboarding abgeschlossen, Dev-Umgebungen laufen, Gate grün | §10 | +| **M1** | Fundament: Schema+Migration+Reseed grün, RLS-Tests grün | WS0, WS6, WS7-Basis | +| **M2** | Login gegen Identity (Two-Step) + Single-Membership-Nutzer landet im Dashboard | WS1, WS5-Login | +| **M3** | Multi-Membership: Auswahl + Wechsel + MFA-Netz + Isolation nachgewiesen | WS2, WS5-Switcher, WS7-Isolation | +| **M4** | Einladungs-Lifecycle (Plattform+Kunde+Wizard), „Passwort setzen" entfernt | WS3 | +| **M5** | Passwort/MFA-Reset auf Identity, Reset raus aus Mandantenverwaltung | WS4 | +| **M6** | Härtung, vollständige Test-Suite, Doku, STAND aktualisiert, Deploy | WS7, Doku | + +--- + +## 8. Risiken & Gegenmaßnahmen +| Risiko | Gegenmaßnahme | +|---|---| +| **RLS kippt**, wenn kein/mehrdeutiger aktiver Mandant | `session.user.tenantId` immer = genau **eine** validierte Membership; fail-closed; Guard wirft bei leer | +| **356 Call-Sites** anfassen | Leitentscheidung §1: `User.id` + `session.user.tenantId`-Semantik erhalten → Call-Sites unverändert | +| **Two-Step „halb angemeldet"-Bypass** | MFA-pending-State ist einzweckig + kurzlebig, **keine** App-Session vor MFA | +| **Rechte veraltet** bei Wechsel ohne Re-Login | `setActiveTenant` löst Permissions **neu** auf (nicht Token-eingefroren) | +| **Breiterer Blast-Radius** eines Credentials | starke Passphrase-Policy + MFA + kurze Session + globaler Kill-Switch (`Identity.sessionsValidAfter`) | +| **Plattform/Tenant-Cookie-Kollision** | bereits gelöst (getrennte Cookie-Namen, `platform-auth.ts`) — beibehalten | +| **Team nicht eingearbeitet** | M0-Onboarding als eigener Meilenstein, „Goldene Regeln" §10, Pair auf WS0 | + +--- + +## 9. Definition of Done +**Pro Story:** tsc + lint + build grün · zugehöriges `scripts/test-*.ts` grün · keine neuen `dbForTenant`-Regressionen · Doku-Schnipsel im PR. +**Gesamt (M6):** alle `scripts/test-*` grün (inkl. **neuer** Isolations-/Enforcement-Tests) · Login/Auswahl/Wechsel/Einladung/Reset im Browser verifiziert · RLS-Test mit Multi-Membership-Nutzer nachweist, dass Wechsel **keine** Fremddaten sichtbar macht · `docs/STAND-dev-branch.md` + dieses Doc aktualisiert · sauber nach `dev` (beide Remotes) integriert. + +--- + +## 10. Onboarding der neuen Entwickler (M0) +**Pflichtlektüre (in dieser Reihenfolge):** `docs/HANDOVER-DEV.md` → `docs/SPEC.md` → `docs/STAND-dev-branch.md` → dieses Doc → [KONZEPT-identity-mandanten.md](KONZEPT-identity-mandanten.md). + +**Dev-Setup:** Node + Postgres (pgvector-Image), `.env` aus `.env.example`, `npx prisma migrate deploy`, Demo-Seed (`RUN_DEMO_SEED`), `npm run dev`. Demo-Logins in `prisma/seed.ts`. + +**Validierungs-Gate (vor jedem PR):** `npx tsc --noEmit` · `npm run lint` · `npm run build` · **alle 17 `scripts/test-*.ts`**. + +**RLS-Mentalmodell (Pflichtverständnis):** `dbForTenant(tenantId)` setzt pro Transaktion `app.tenant_id`; `TENANT_MODELS` sagt, welche Modelle mandantengefiltert sind; globale Modelle (Kataloge, künftig `Identity`) laufen über den Owner-`prisma`. **Nie** ein globales Modell in `TENANT_MODELS` aufnehmen und **nie** ein tenant-Modell ohne Kontext lesen. + +**DevOps-Workflow:** Feature-Branch → `git merge --no-ff` nach `dev` → Gate grün → Push auf **beide** Remotes (`origin` = git.certvia.de, `local-gitea`) → `docs/STAND-dev-branch.md` pflegen. (certvia ist strikt getrennt von anderen Produkten — nichts vermischen.) + +**Goldene Regeln dieses Umbaus:** +1. `User.id` = Mitgliedschaft, **stabil lassen**. Auth-Felder leben auf `Identity`. +2. `Identity` ist **global**, **nicht** in `TENANT_MODELS`, kein `tenant_id`, keine RLS-Policy. +3. Genau **ein** aktiver Mandant pro Session; server-autoritativ; bei Wechsel re-validieren. +4. **Keine** „Passwort direkt setzen"-Anlage mehr — nur Einladung. +5. MFA/Passwort gehören der Identity — **kein** Mandanten-Admin-Reset. + +--- + +## 11. Rollen & Cadence (Beispielbesetzung: 1 Lead + 2 Devs + PM) +| Rolle | Verantwortung | +|---|---| +| **Tech-Lead / Senior** | WS0 + WS1 (Fundament + Auth-Kern), Review aller Auth-/RLS-PRs, Sicherheitskontrollen §8 | +| **Dev A** | WS2 (Mandantenkontext/Guards) + WS5 (UI) | +| **Dev B** | WS3 (Einladung) + WS4 (Passwort/MFA an Identity) + WS6 (Seed) | +| **alle** | WS7 (jede Story bringt ihren Test) | +| **PM** | Meilenstein-Tracking (§7), Risiken (§8), DoD-Abnahme (§9), Entscheidungs-Eskalation (Phase-2-Punkte), Cadence | + +**Cadence-Vorschlag:** WS0 als **Pairing** (Lead + je 1 Dev) — dient zugleich als Onboarding-Vehikel; danach 2-Wochen-Iterationen entlang M1–M6, Demo je Meilenstein, PR-Review verpflichtend für Auth/RLS. + +--- + +## 12. Aufwandsschätzung (grob, Personentage) +> Annahme: 3 Devs, noch nicht eingearbeitet → Ramp-up eingepreist. Ohne Produktivdaten-Migration (Entscheidung D). + +| Block | PT (Bereich) | +|---|---| +| M0 Onboarding (3 Personen) | 6–9 | +| WS0 Fundament + Migration + Reseed | 5–8 | +| WS1 Auth-Kern (Two-Step, Session-Shape) | 8–12 | +| WS2 Mandantenkontext + Guards + Switcher | 6–9 | +| WS3 Einladungs-Lifecycle | 5–8 | +| WS4 Passwort/MFA an Identity | 6–9 | +| WS5 UI | 4–6 | +| WS6 Seed/Provision/Bootstrap | 2–4 | +| WS7 Tests & Härtung | 5–8 | +| **Summe** | **≈ 47–73 PT** | + +**Kalenderdauer** bei 3 Devs mit Parallelisierung (§6) + PM-Overhead: **≈ 5–7 Wochen** bis M6 (inkl. Onboarding-Woche). Kritischer Pfad: **WS0 → WS1 → WS2 → WS5**. WS3/WS4/WS6 laufen daneben. + +--- + +## 13. Phase 2 (bewusst später, kein Blocker) +- Per-Mandant-Schalter „bei jedem Betreten Step-up erzwingen" (Hochsicherheits-Kunden). +- E-Mail-Änderung als Identity-Operation (Sonderfälle/Merge). +- Optionale Konsolidierung `PlatformAdmin` in die `Identity` (Store getrennt lassen, nur Verweis). diff --git a/docs/FRAMEWORK-MAPPING-ISO27001.md b/docs/FRAMEWORK-MAPPING-ISO27001.md new file mode 100644 index 0000000..56dbfdc --- /dev/null +++ b/docs/FRAMEWORK-MAPPING-ISO27001.md @@ -0,0 +1,150 @@ +# ISO/IEC 27001:2022 auf der gemeinsamen Dokumentenbibliothek (Variante A) + +**Stand:** 2026-08-27 · **Paket:** `seed/isms-vorlagenpaket-v2` (+ `-en`) · **Status:** umgesetzt, ISB-Freigabe offen + +> **Entscheidung:** Ein Dokumentensatz, zwei Framework-Mappings. Die bestehenden Richtlinien und +> Verfahren bleiben die einzige Quelle; ISO/IEC 27001 wird als zweites Mapping darübergelegt. +> Damit ersetzt diese Umsetzung die ursprüngliche Annahme aus `KONZEPT-framework-iso27001.md` +> (D4: zweites Seed-Paket `seed/isms-iso27001-v1/`). + +--- + +## 1. Warum nicht zwei Pakete + +`PolicyDocument` ist über `@@unique([tenantId, code])` eindeutig. Zwei Pakete mit denselben +Dokument-Codes (`L00`, `R01`…`R14`, `VA-01`…`VA-20`) können in einem Mandanten nicht nebeneinander +existieren — der zweite Import überschreibt beim Upsert den Inhalt des ersten und archiviert die +Dokumente, die im anderen Paket fehlen. Für einen Mandanten mit ISO **und** TISAX wäre das Ergebnis +das Gegenteil der Absicht. + +Hinzu kommt der fachliche Punkt: Die Umsetzungsbeschreibung („Umsetzung bei {{ORG_NAME}}") ist +normunabhängig. Wie eine Organisation Berechtigungen vergibt, ändert sich nicht dadurch, ob ISO oder +VDA ISA danach fragt. Sie zweimal zu pflegen erzeugt Widersprüche. + +## 2. Aufbau + +| Bestandteil | Rolle | +|---|---| +| `richtlinien/`, `verfahren/` | **gemeinsame** Dokumente — ein Umsetzungstext je Thema | +| `mapping.json` | Framework-Mapping **VDA ISA 2027** (321 Anforderungen) | +| `mapping-iso.json` | Framework-Mapping **ISO/IEC 27001:2022** (120 Anforderungen) | +| `_iso_crosswalk.json` | fachliche Zuordnung ISO-Anforderung → Dokument + Abschnitt (redaktionell) | +| `_iso_sections.json` / `_iso_sections_en.json` | Texte der ISO-only-Abschnitte (redaktionell, je Sprache) | +| `_iso_texts_en.json` | englische Anforderungstexte (Struktur bleibt im Crosswalk) | +| `_generate_iso.py` | erzeugt aus beidem die Dokument-Patches, `mapping-iso.json` und die SoA | +| `_verify.py` / `_verify_iso.py` | prüfen je eine Framework-Sicht | +| `Statement-of-Applicability-ISO.md` | SoA-Gerüst mit den Pflichtangaben aus 6.1.3 d) | + +### Sichtbarkeitssteuerung über Platzhalter + +Zwei neue Flags in `variables.schema.json` steuern, welche Anforderungssicht ein Mandant sieht: + +| Flag | Default | Wirkung | +|---|---|---| +| `FLAG_FW_TISAX` | `true` | VDA-ISA-Anforderungsblöcke sichtbar | +| `FLAG_FW_ISO27001` | `false` | ISO-Anforderungsblöcke und ISO-only-Abschnitte sichtbar | + +Im Dokument sieht das so aus — der Umsetzungstext steht **einmal** und gilt für beide: + +```markdown +### 3.2 Sichere Anmeldung + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.5{{/if}} + +**Anforderung** + +{{#if FLAG_FW_TISAX}} +- **[MUSS]** Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt. +{{/if}} +{{#if FLAG_FW_ISO27001}} +- **[ISO A.8.5]** Sichere Authentisierungstechnologien und -verfahren sind einzusetzen. +{{/if}} + +**Umsetzung bei {{ORG_NAME}}** + + +Die Authentifizierungsverfahren sind risikobasiert ausgewählt … Passwortvorgaben nach BL-IAM-01 … +``` + +Beide Mappings zeigen mit `impl_anchor` auf denselben Block `IMPL 4.1.2`. + +## 3. Abdeckung + +- **120 ISO-Anforderungen:** 27 Klauseln (Kap. 4–10, inkl. 6.3 aus Amd 1:2024) + 93 Anhang-A-Controls + in der Verteilung 37/8/14/34. +- **43 Abschnitte** der Bibliothek werden von beiden Frameworks genutzt. +- **19 ISO-only-Abschnitte** wurden ergänzt, wo VDA ISA kein Gegenstück hat: + +| Dokument | Neue Abschnitte | ISO-Bezug | +|---|---|---| +| L00 | Politik, Ziele, Kommunikation | 5.2, 6.2, 7.4, A.5.1 | +| R01 | Kontext/Scope · Änderungsplanung · Dokumentenlenkung · Behördenkontakte | 4.1–4.4, 6.3, 7.5.1–7.5.3, A.5.5, A.5.6 | +| R02 | Datenmaskierung | A.8.11 | +| R03 | SoA · Betriebliche Planung · Messung · Managementbewertung · CAPA | 6.1.3, 8.1, 9.1, 9.3, 10.1, 10.2 | +| R05 | Vorgehen bei Verstößen | A.6.4 | +| R07 | Umgebungsschutz/Versorgung/Verkabelung/Wartung · Clear Desk | A.7.5, A.7.7, A.7.8, A.7.11–A.7.13 | +| R10 | Bedrohungsinformationen · Betriebsabläufe · Kapazität · Datenabfluss · Zeitsynchronisation | A.5.7, A.5.37, A.8.6, A.8.12, A.8.17 | + +Die neuen Abschnitte sind ausschließlich über Platzhalter individualisierbar — wie die +Bestandstexte. Dafür kamen elf Variablen und acht Baseline-Parameter hinzu +(`BL-OPS-10/11/12`, `BL-NET-03`, `BL-PHY-03/04`, `BL-GOV-02/03`). + +**Ohne ISO-Bezug** bleibt nur der Abschnitt „Nutzung von KI-/GenAI-Diensten" (eigene Ergänzung) sowie +die Dokumente `P01` (Prototypenschutz) und `D01` (Datenschutz-Prüfziel) — beides TISAX-spezifisch. + +## 4. Änderungen am Anwendungscode + +Zwei Stellen, beide klein und rückwärtskompatibel: + +1. **`prisma/import-policies.ts`** — der Umsetzungstext wird jetzt über `impl_anchor` aufgelöst + (`IMPL 4.1.2`), mit Rückfall auf die Anforderungs-ID und auf ein `implementation`-Feld im Mapping. + *Nebeneffekt:* Das behebt einen Bestandsfehler. Bisher wurde `implMap.get(a.id)` gesucht — die + Anforderungs-IDs (`4.1.2-M1`) haben aber keinen eigenen IMPL-Block, sodass **alle 321** + VDA-ISA-Anforderungen mit leerem Umsetzungstext importiert wurden. Sichtbar war das u. a. in der + Spalte „Umsetzung" unter `/policies` und in der Plattform-Vorlagenverwaltung. Nach der Korrektur + bleiben 12 leere Einträge (L00 — die Leitlinie hat bewusst keine IMPL-Blöcke). +2. **`src/lib/policy-render.ts`** — `buildContext` belegt fehlende Framework-Flags vor + (`FLAG_FW_TISAX = true`, `FLAG_FW_ISO27001 = false`). Ohne das würden Bestandsmandanten, deren + Vorlagenpaket noch nicht neu importiert wurde, die VDA-ISA-Anforderungsblöcke leer sehen. + +## 5. Prüfung + +```bash +cd seed/isms-vorlagenpaket-v2 +python3 _generate_iso.py # deutsche Fassung, idempotent +python3 _generate_iso.py --lang en # englische Fassung +python3 _verify.py # TISAX-Sicht → OK +python3 _verify_iso.py # ISO-Sicht DE → OK +python3 _verify_iso.py --lang en # ISO-Sicht EN → OK +``` + +`_verify_iso.py` prüft Vollständigkeit (27 + 93), Auflösbarkeit aller Anker, nicht leere +Umsetzungsblöcke, das Rendering **beider** Sichten ohne offene Platzhalter sowie die Verknüpfung zu +den Verfahren. + +## 6. Was noch fehlt (Anwendungsseite) + +Das Paket ist fertig; die Anwendung kennt das zweite Mapping noch nicht. Offen bleibt aus +`KONZEPT-framework-iso27001.md`: + +- **Lane 1** — `Framework`-Enum, `TenantFramework`, `framework` an `PolicyTemplateVersion` und + `PolicyPackageState`. Erst damit lässt sich `mapping-iso.json` überhaupt importieren; heute liest + `parsePackageFiles` fest `mapping.json`. +- **Lane 3/4** — ISO-Assessment (Applicability statt Reifegrad) und das **SoA-Modul**. Bis dahin wird + die SoA als gelenktes Dokument geführt (`Statement-of-Applicability-ISO.md`). +- **Setzen der Flags** — beim Provisionieren eines ISO-Mandanten müssen `FLAG_FW_ISO27001 = true` + und, falls kein TISAX, `FLAG_FW_TISAX = false` gesetzt werden. + +Ebenfalls offen und unabhängig davon: `REVIEW_CYCLE` wird weiterhin für fünf verschiedene Zyklen +verwendet. Die neuen Abschnitte nutzen bereits die getrennten Variablen +(`POLICY_REVIEW_CYCLE`, `MGMT_REVIEW_CYCLE`, `RISK_REVIEW_CYCLE`); die Bestandstexte umzustellen ist +eine eigene, kleine Änderung. + +## 7. Urheberrechtlicher Hinweis + +Die ISO-Anforderungstexte in `mapping-iso.json` und in den Dokumenten sind **eigene Paraphrasen**; +die Referenzen sind exakt, damit in der erworbenen Norm nachgeschlagen werden kann. Wörtliche +Normzitate sind bewusst unterlassen. Das VDA-ISA-Mapping übernimmt die Anforderungen laut eigenem +Hinweis in `mapping.json` „1:1 aus ISA" — auch dieser Katalog ist geschützt. Bei der weiteren Pflege +der gemeinsamen Bibliothek sollte die vorsichtigere Linie des ISO-Mappings die gemeinsame werden +(vgl. `SPEC.md` §12). diff --git a/docs/HANDBUCH-KUNDENBETREUUNG.md b/docs/HANDBUCH-KUNDENBETREUUNG.md new file mode 100644 index 0000000..6606d6f --- /dev/null +++ b/docs/HANDBUCH-KUNDENBETREUUNG.md @@ -0,0 +1,83 @@ +# Handbuch Kundenbetreuung — certvia (ISMS-Tool) + +**Stand:** 2026-09-03 · **Zielgruppe:** Kundenbetreuung / Customer Success · **Zweck:** Schneller, praxisnaher Einstieg für die Betreuung von certvia-Kunden — was das Produkt kann, wie ein Kunde aufgesetzt/betreut wird und wie typische Support-Fälle gelöst werden. + +> Dieses Handbuch ist bewusst **produkt- und supportorientiert**. Technische Tiefe steht in `docs/SPEC.md`, `docs/HANDOVER-PM.md` und den `docs/KONZEPT-*.md`. + +--- + +## 1. Was ist certvia (in einem Absatz) + +certvia ist ein **Multi-Mandanten-ISMS-Tool** (Informationssicherheits-Managementsystem als SaaS). Jeder Kunde ist ein **Mandant** mit strikt getrennten Daten. Das Tool führt einen Kunden vom Onboarding über Strukturanalyse (Assets/Prozesse/Lieferanten), Risikomanagement, Richtlinien und Maßnahmen bis zur **Audit-Vorbereitung** — wahlweise nach **TISAX (VDA-ISA)** und/oder **ISO 27001**. + +## 2. Zugang, Rollen, Anmeldung + +- **Kunden-Login:** `https:///login` — E-Mail + Passwort, danach ggf. MFA (TOTP) und, bei mehreren Mandanten, Mandantenauswahl. +- **Plattform-/Superadmin:** `…/platform/login` — **getrennter Login** für die Betreiber-Administration (Mandanten anlegen, Module, Stammdaten). MFA-Einrichtung beim ersten Login. +- **Rollen (mandantenintern):** z. B. Mandanten-Admin, ISB (Informationssicherheitsbeauftragter), Auditor, Owner, User. Rechte hängen an Rollen; der **Mandanten-Admin** verwaltet Benutzer & Rollen unter **Einstellungen → Benutzer & Rollen**. +- **Passwort/MFA:** Initial-/Reset-Passwörter erzwingen einen Wechsel beim nächsten Login. MFA und Passkeys sind an die **Person (Identity)** gebunden, nicht an den Mandanten. + +## 3. Einen neuen Kunden aufsetzen (Provisionierung) + +Ein Kunde wird als **Mandant** angelegt (über die Plattform-/Superadmin-Konsole bzw. beim ersten Deployment per Bootstrap-Admin). Beim Anlegen wird automatisch: +- ein **Mandanten-Admin** erzeugt, +- die **Standard-Module** aktiviert, +- das **Richtlinien-Vorlagenpaket** importiert (inkl. Anforderungen, Variablen, Nachweisregister), +- das **Framework** gesetzt (Default **TISAX**; ISO 27001 ist zusätzlich/alternativ wählbar). + +Die **Stammdaten** des Mandanten (Firmenname, Kürzel, Rollen wie ISB/IT-Leitung/DSB, Scope) pflegt der Kunde unter **Einstellungen** — diese speisen automatisch die ISMS-Variablen in den Richtlinien. + +## 4. Framework-Wahl: ISO 27001 und/oder TISAX + +- Ein Mandant kann **ein oder beide** Frameworks führen. Der Umsetzungstext der Richtlinien ist normunabhängig; je Framework gibt es eine eigene Katalog-/Anforderungssicht. +- **TISAX (VDA-ISA):** Reifegrad-Modell, Schutzbedarf/Assessment-Level (AL2/AL3), Prüfziele (Informationssicherheit/Prototypen/Datenschutz), VDA-ISA-Export. +- **ISO 27001:** Anwendbarkeitserklärung (SoA, Annex A 2022, 93 Controls) mit „anwendbar/ausgeschlossen + Begründung", Managementklauseln (Kennzahlen 9.1, Managementbewertung 9.3, Korrekturmaßnahmen 10.2) und Dokumentenlenkung. +- **Umschalten:** In der Admin-Konsole lassen sich die Normen je Mandant **nachträglich aktivieren/deaktivieren**. + +## 5. Die Module (Kurzüberblick) + +| Modul | Zweck | +|---|---| +| **Assets** | Informationswerte/Systeme/Anwendungen etc. inkl. Schutzbedarf (C/I/V) | +| **Prozesse** | Geschäftsprozesse + Verknüpfung zu Assets (Strukturanalyse) | +| **Risiken** | Risiko-Register (Eintritt × Auswirkung), Behandlung, Verknüpfung zu Assets/Prozessen | +| **Lieferanten** | Lieferanten-/Dienstleistersteuerung (Kritikalität, NIS2, TISAX-Label, Verträge/NDAs) | +| **Maßnahmen** | Maßnahmen zur Risikobehandlung, Wirksamkeit | +| **Richtlinien** | Richtlinien-/Verfahrensbibliothek aus Vorlagen, Freigabe, Coverage | +| **SoA** | ISO-Anwendbarkeitserklärung bzw. TISAX-Control-Assessment | +| **Audit-Readiness** | Reifegrad/Gap-Analyse, Nachweise, Abgabe/Export | +| **Vorfälle** | Incident-Management (inkl. NIS2-/DSGVO-Meldevorlagen) | +| **Aufgaben** | Kanban-Aufgaben, Fristen | + +Module lassen sich je Mandant **ein-/ausschalten** (Admin-Konsole). + +## 6. Onboarding-Wizard + +Neue Mandanten durchlaufen einen geführten Wizard: **Kontext → Scope → Richtlinien → Rollen → Risikokriterien → Prozesse → Controls**. Er baut das ISMS Schritt für Schritt auf; der Fortschritt wird gespeichert. + +## 7. Typische Support-Fälle + +- **„Login klappt nicht / Anmeldung fehlgeschlagen":** falsche E-Mail/Passwort, oder Account nach mehreren Fehlversuchen kurz gesperrt (15 Min). Prüfen: richtige Seite (`/login` vs `/platform/login`), Passwort exakt. Bei Reset ein Initial-Passwort setzen (erzwingt Wechsel). +- **„MFA-Gerät verloren":** über Recovery-Codes anmelden; sonst MFA administrativ zurücksetzen (Mandanten-Admin/Betreiber). +- **„Ein Modul fehlt in der Navigation":** Modul ist für den Mandanten deaktiviert → in der Admin-Konsole aktivieren. +- **„Falsche Norm / ISO fehlt":** Framework des Mandanten prüfen und ggf. ISO 27001 aktivieren (Admin-Konsole). +- **„E-Mails kommen nicht an":** SMTP-Konfiguration prüfen (Betreiber); Postfach/From-Adresse. + +## 8. Wo finde ich vertiefende Infos? + +- **Produkt/Funktionsumfang:** `docs/SPEC.md`, `docs/HANDOVER-PM.md` +- **Kundennahe Mockups (im Browser):** `docs/ISMS-Prototyp-GEFIM.html`, `ISMS-Lieferantenmanagement-GEFIM.html` +- **Feature-Konzepte:** `docs/KONZEPT-framework-iso27001.md` (ISO/TISAX), `KONZEPT-incidents.md`, `KONZEPT-backup-restore.md`, `KONZEPT-identity-mandanten.md` (Login/Mandanten/MFA) +- **Aktueller Stand/Änderungen:** `docs/STAND-dev-branch.md` +- **Am besten:** die **Demo-/Testinstanz** durchklicken (Login `admin@demo.example` / `Demo1234!`). + +## 9. Betrieb & Grenzen (gut zu wissen) + +- **Test- vs. Produktivumgebung:** Änderungen werden erst auf einer Testinstanz erprobt, dann produktiv ausgerollt. Support arbeitet auf der Produktivumgebung nur mit Bedacht. +- **Backups:** Datenbank + Objektspeicher werden gesichert (Betrieb). Restore ist möglich; keine eigenmächtigen Löschaktionen an Produktivdaten. +- **Datenschutz/Mandantentrennung:** Jeder Mandant sieht nur seine eigenen Daten — niemals Kundendaten zwischen Mandanten kopieren. +- **Secrets/Zugänge:** niemals per E-Mail/Chat weitergeben; Passwörter setzt der Kunde selbst bzw. als Initial-Passwort mit Wechselzwang. + +--- + +*Fehlt etwas oder ist ein Support-Fall unklar? Ergänze dieses Handbuch — es ist als lebendes Dokument gedacht.* diff --git a/docs/HANDOVER-DEV.md b/docs/HANDOVER-DEV.md new file mode 100644 index 0000000..f07a5df --- /dev/null +++ b/docs/HANDOVER-DEV.md @@ -0,0 +1,197 @@ +# Entwickler-Übergabe — ISMS-Tool + +> 📌 **Aktueller Gesamtstand des `dev`-Branches (alle Entwicklungstätigkeiten, PM + Dev):** siehe **`docs/STAND-dev-branch.md`**. + +> Stand: 2026-07-22 · Branch `dev` (Produktionshärtung + Benutzerverwaltung) · Basis `main` +> Zweck: Kontext, Setup und Konventionen, damit ein neuer Entwickler direkt weiterarbeiten kann. +> Fachlicher Status (fertig/offen) siehe **`docs/HANDOVER-PM.md`**. Neue Härtungs-/Verwaltungspakete: §10. + +--- + +## 1. Repository & Zugriff + +- **Lokaler Pfad:** `~/Projects/ISMS-Tool` +- **Git-Remote (Gitea, nur HTTP):** + `http://gitea-vkbhbn2qdkz5ppk9q4qgb0tn.192.168.1.207.sslip.io/msolarczek/ISMS-Tool.git` + (interner Server; kein SSH). **Zugangstoken** liegt im macOS-**Schlüsselbund** (nicht im Repo, nicht in Klartext weitergeben). Für `git push` wird der Token als HTTP-Passwort verwendet. +- **Default-Branch:** `main` (es wird direkt auf `main` committet; Commits sind fein granular je Thema). +- **Commit-Konvention:** deutschsprachige, aussagekräftige Messages; Referenz auf Spec-Abschnitte (z. B. „§7b"). Co-Authored-By-Trailer für KI-Beiträge. + +--- + +## 2. Tech-Stack (verifizierte Versionen) + +| Bereich | Technologie | +|--------|-------------| +| Runtime | **Node.js 26** | +| Framework | **Next.js 16** (App Router, React 19, Server Components + Server Actions, Turbopack im Dev) | +| Sprache | TypeScript (strict) | +| DB / ORM | **PostgreSQL** (mit **pgvector**) · **Prisma 7** (`@prisma/client` + `@prisma/adapter-pg`, `prisma.config.ts`) | +| Auth | **NextAuth v5** (Credentials, JWT-Session) · Passwörter mit `@node-rs/argon2` | +| i18n | **next-intl** (Default `de`, `en` vorbereitet; Catalog in `messages/de.json`/`en.json`) | +| UI | Tailwind **v4** + shadcn/ui (**Base-UI-Variante**), Dark-Theme über zentrale CSS-Tokens in `src/app/globals.css` | +| Spezial | Handlebars + `marked` (Richtlinien-Rendering), `@xyflow/react` + `@dagrejs/dagre` (Abhängigkeitsgraph), `zod` (Validierung) | + +**Scripts** (`package.json`): `dev` (`next dev`), `build`, `start`, `lint` (`eslint`). Seed: `npx tsx prisma/seed.ts`. + +--- + +## 3. Setup (von Null) + +```bash +# 1. Repo klonen (Token als HTTP-Passwort) +git clone http://gitea-…/msolarczek/ISMS-Tool.git +cd ISMS-Tool + +# 2. Abhängigkeiten +npm install + +# 3. .env anlegen (Vorlage vorhanden) +cp .env.example .env +# Wichtige Variablen: DATABASE_URL (Postgres inkl. pgvector), AUTH_SECRET, AUTH_URL, +# optional REDIS_URL, AI_PROVIDER/AI_API_KEY, SMTP_* (noch ungenutzt). + +# 4. Infrastruktur starten (docker-compose.yml im Repo-Root) +docker compose up -d postgres # Postgres mit pgvector (Image pgvector/pgvector:pg16) +# Weitere Services im Compose: app, worker, redis, minio (Objektspeicher, für späteren +# Logo-Upload), mailhog (SMTP-Dev). Für lokale Entwicklung reicht i. d. R. 'postgres'. + +# 5. Prisma-Client + Migrationen +npx prisma generate +npx prisma migrate deploy # wendet alle Migrationen an (inkl. RLS-Policies) + +# 6. Seed (Demo-Mandant, Kataloge, Richtlinienpaket, Admin-Konsole) +npx tsx prisma/seed.ts + +# 7. Dev-Server +npm run dev # http://localhost:3000 (Port 3000, siehe .claude/launch.json) +``` + +**Demo-Logins** (Passwort `Demo1234!`): `admin@demo.example` (Mandanten-Admin + ISB), `bea.approver@demo.example` (ISB, zweiter Freigeber für den Vier-Augen-Workflow), `auditor@demo.example`, `owner@demo.example`, `user@demo.example` — alle über den **Mandanten-Login** `/login`. + +**Plattform-Admin (Betrieb):** getrennter Store + eigener Login `/platform/login` (TOTP-MFA-Pflicht, Enrollment beim ersten Login). Demo-Konto: `admin@demo.example` / `Demo1234!` (gleiche Adresse, aber getrennte Session ohne Mandantenkontext). Das frühere `isPlatformAdmin`-Flag ist abgelöst; die Admin-Konsole `/admin` ist nur mit Plattform-Session erreichbar. Siehe **Paket 2** der Produktionshärtung. + +--- + +## 4. Architektur & tragende Konventionen + +### Mandantenfähigkeit (kritisch!) +- Jede Fachtabelle hat `tenant_id`. **Nie ohne Mandantenkontext queren.** +- Zentraler Guard **`dbForTenant(tenantId)`** in `src/server/db.ts`: filtert reads automatisch nach `tenantId`, injiziert ihn bei `create`, prüft Ownership bei `findUnique`/`update`/`delete`. Neue tenant-bezogene Modelle **müssen in `TENANT_MODELS`** (in `db.ts`) eingetragen werden. +- Zusätzlich **Postgres Row Level Security** je Tabelle (Policy `tenant_isolation`, gesetzt in den Migrationen). Superadmin/plattformweite Reads laufen über den **rohen `prisma`**-Client (nicht `dbForTenant`). +- Session (`src/server/auth.ts`) trägt `tenantId`, `roles`, `permissions`, `isPlatformAdmin`. + +### RBAC +- Katalog + Rollen-Blueprints in **`src/server/rbac.ts`** (`PERMISSIONS`, `ROLE_DEFS`). Serverseitige Durchsetzung: `requirePermission(session, "x:y")` / `hasPermission(...)`. UI-Verstecken ist nur Komfort. + +### Modul-Gating (§3.4) +- Modul-Katalog in **`src/lib/modules.ts`**. Je Mandant `TenantModule`-Zeilen (enabled). Navigation blendet deaktivierte Module aus (`layout.tsx`). +- **Serverseitige Durchsetzung:** `requireModule("key")` in `src/server/modules.ts`, angewandt als **Modul-`layout.tsx`** je Routenordner (`assets/`, `processes/`, `risks/`, `measures/`, `policies/`, `suppliers/`, `dependencies/`) → schützt auch Unterrouten. In Server-Actions läuft der Layout-Guard erst nach der Mutation, daher zusätzlich `requireModule` im Action-`guard()` (bisher exemplarisch nur `policies.ts` — **auf übrige Action-Dateien nachzuziehen**). + +### UI-Muster +- **Detail/Bearbeiten/Anlegen** überwiegend als **URL-gesteuerte Popups** (`?detail=`/`?edit=`/`?new=1`, `src/components/modal.tsx`) — Ausnahme: **Richtlinien-Dokumente** wurden bewusst auf **eigene Seiten** (`/policies/[code]`, `.../edit`) umgestellt. +- Dark-Theme: **keine hartkodierten Hex-Werte** in Komponenten — zentrale Tokens verwenden (`--bg-0`, `--panel`, `--surface-soft`, `--band`, `--ok/--warn/--risk/--info`, …). +- Formulare mit „einem Speichern-Button" nutzen HTML-`form`-Attribut-Assoziation (`form="id"`). +- Alle sichtbaren Texte über den next-intl-Catalog (`messages/*.json`) — Admin-/Register-Detailtexte teils bewusst inline-Deutsch. + +### Prisma-7-Migrationen (Eigenheit) +Nicht-interaktiv, in zwei Schritten: +```bash +npx prisma migrate diff --from-config-datasource prisma.config.ts \ + --to-schema prisma/schema.prisma --script > prisma/migrations/_name/migration.sql +# RLS-DO-Block manuell an die migration.sql anhängen (siehe bestehende Migrationen) +npx prisma migrate deploy +``` +(Die interaktiven `migrate dev`-Prompts sind in dieser Umgebung blockiert; Flag-Namen in Prisma 7 geändert: `--from-config-datasource`/`--to-schema`.) + +--- + +## 5. Verzeichnisstruktur (Auszug) + +``` +src/ + app/(app)/ # geschützter App-Bereich (Sidebar-Shell = layout.tsx) + dashboard/ assets/ processes/ risks/ measures/ dependencies/ suppliers/ + policies/ # Richtlinien: page + [code]/(page,edit) + layout.tsx (Modul-Guard) + admin/ admin/[id]/ # Plattform-Admin-Konsole (Superadmin) + settings/ # Kunden-Einstellungen (tenant:manage) + app/login/ # Login + components/ # UI + Fach-Modals (asset-, supplier-, service-, policy-*.tsx …) + server/ + auth.ts db.ts rbac.ts modules.ts provision.ts audit.ts + risk-calc.ts dependency-graph.ts + actions/ # Server Actions je Modul (assets, risks, measures, suppliers, + # services, policies, admin, tenant-settings) + lib/ # modules, policy-render, supplier(+include), risk, control-titles, + # isa-controls, levels, measure, utils +prisma/ + schema.prisma seed.ts import-policies.ts import-managed.ts migrations/ +messages/ de.json en.json +seed/isms-vorlagenpaket-v2/ # VDA-ISA-Vorlagenpaket (Richtlinien/Verfahren, mapping.json, Baseline …) +docs/ SPEC.md HANDOVER-PM.md HANDOVER-DEV.md *.html (Mockups) +``` + +--- + +## 6. Modul-Kurzreferenz (wo liegt was) + +- **Richtlinien:** Rendering-Engine `src/lib/policy-render.ts` (Handlebars, Flags, BL-Entfernung, `applyProtection` für TISAX-Level), Import `prisma/import-policies.ts` + `prisma/import-managed.ts`, UI `src/app/(app)/policies/**` + `src/components/policy-*.tsx`, Actions `src/server/actions/policies.ts`. Control-Titel `src/lib/control-titles.ts`. +- **Lieferanten/IT-Service:** Engine `src/lib/supplier.ts`, Includes `src/lib/supplier-include.ts`, UI `src/components/supplier-modals.tsx`/`service-modals.tsx`/`supplier-cockpit.tsx`, Actions `suppliers.ts`/`services.ts`. +- **Admin/Mandanten:** Provisionierung `src/server/provision.ts` (von Seed **und** `actions/admin.ts` genutzt, idempotent), `actions/tenant-settings.ts` (Stammdaten → ISMS-Variablen via `syncPolicyVariablesFromSettings`). +- **Risiko/Graph:** `src/server/risk-calc.ts`, `src/server/dependency-graph.ts`, `src/lib/risk.ts`. + +--- + +## 7. Datenmodell — zentrale Modelle + +`Tenant`, `TenantSettings` (Quelle der ISMS-Variablen), `TenantModule`, `User` (`isPlatformAdmin`), `Role`/`Permission`/`RolePermission`/`UserRole`, `AuditLog` (`scope: tenant|platform`). +Fachlich: `Asset`/`AssetRelation`, `Process`/`ProcessAsset`/`BiaEntry`, `Risk`/`RiskAsset`/`Measure`/`RiskMeasure`, `Threat`/`Vulnerability`, `SupplierProfile`/`ITServiceProfile` (+ Assessments/Contracts/Ndas/Evidence/Raci/Maturity), Richtlinien: `PolicyDocument`/`PolicyRequirement`/`PolicyVariable`/`PolicyBaselineParam`/`PolicyEvidence` + verwaltete Register (`CryptoEntry`, `ClassificationClass`/`HandlingAspect`/`HandlingRule`, `RiskMatrixClass`/`RiskEwLevel`/`RiskDamageDimension`, `HandbookTopic`). + +--- + +## 8. Verifikations-Workflow + +Nach jeder Änderung: **`npx tsc --noEmit`** → **`npm run lint`** → **`npm run build`**. Danach – wo relevant – Browser-Verifikation (Dev-Server + Login `admin@demo.example`). Bei DB-Änderungen: Migration erzeugen/anwenden + `npx tsx prisma/seed.ts` neu laufen lassen. Für das Richtlinien-Rendering existiert ein Residue-Check-Muster (rückstandsfrei über Flag-Kombinationen, angelehnt an `seed/.../_verify.py`). + +--- + +## 9. Bekannte Fallstricke + +1. **Beschädigte Seed-Tokens:** Das VDA-ISA-Paket enthält in einigen VA-RACI-Tabellen (VA-05/08/09/10/12/13) abgeschnittene `{{VAR |`-Tokens. Bei jedem Paket-Update **erneut prüfen & reparieren** (sonst bricht Handlebars). Scan: unbalancierte `{{`/`}}` je Zeile. +2. **Richtlinien-Re-Import ist nicht-destruktiv** (Phase-1-Härtung Paket 3, `prisma/import-policies.ts`): Diff/Upsert über stabile Schlüssel (`code`/`reqId`/`key`/`blId`/`nr`). Vorhandenes wird inhaltlich aktualisiert, aber **Status/Override/Freigabe** (PolicyDocument) und **nutzergepflegte Variablenwerte** bleiben erhalten; entfernte Paket-Einträge werden **deaktiviert** (`archivedAt`) statt gelöscht (aktive Ansichten filtern `archivedAt: null`). Verwaltete Register aus `import-managed.ts` (CRYPTO/RISKMATRIX/CLASSIFICATION/HANDBUCH) liegen außerhalb des Paket-Namensraums und werden nicht angetastet. Jeder Lauf liefert einen Änderungsreport (Audit-Log, Entity `policy_package`); `{ dryRun: true }` erzeugt die Vorschau ohne Schreibzugriff. Akzeptanztest: `npx tsx scripts/test-reimport.ts`. +3. **RLS-Kontext:** RLS-Policies erwarten `current_setting('app.tenant_id')`. Die App nutzt primär den `dbForTenant`-Guard; wenn direkte DB-Zugriffe hinzukommen, `app.tenant_id` in der Transaktion setzen. +4. **Turbopack-HMR** kann veraltete Fehler/`MISSING_MESSAGE` zeigen, nachdem `messages/*.json` geändert wurde → Dev-Server neu starten. Produktions-Build ist maßgeblich. +5. **Prisma-7-Migrationsflow** wie in §4 (kein `migrate dev`). +6. **`.next`-Cache** nicht löschen, während der Dev-Server läuft (Turbopack-Korruption) → Server stoppen, `rm -rf .next`, neu starten. +7. **TISAX-Flags:** `FLAG_HIGH_PROTECTION` ist im Modell stets aktiv, `FLAG_ELEVATED_PROTECTION` wird **abgeleitet** (`applyProtection`) — nie manuell setzen. Effektiver Level = Dokument-Override sonst global. + +--- + +## 10. Produktionshärtung & Benutzerverwaltung (umgesetzt, Branch `dev`) + +Aufbauend auf dem Fundament wurden mehrere Härtungspakete umgesetzt (feingranulare Commits auf `dev`): + +- **API-Modul-Durchsetzung (§3.4):** zentraler `moduleGuard("")` in `src/server/action-guard.ts`; jede mutierende Action eines gegateten Moduls läuft über `guard(...)` (Session → `assertModuleEnabled` → RBAC). Vollständigkeitscheck `scripts/check-module-guards.ts` (Registry Action→Modul) als `prebuild` — Build failt bei nicht zugeordneter Action-Datei. Neue Action-Datei ⇒ dort eintragen (Modul-Key oder `EXEMPT`). +- **Plattform-Admins getrennt:** Store `PlatformAdmin` (kein `tenant_id`), eigene NextAuth-Instanz `src/server/platform-auth.ts` (eigener Cookie/basePath `/api/platform-auth`, Session ohne Tenant), Login `/platform/login`, Bereich unter `src/app/(platform)/…`. **MFA (TOTP, `src/server/mfa.ts`) ist optional** — Enrollment nur erzwungen, wenn `PlatformSetting.mfaRequired` (Singleton) an ist; Umschaltung + Self-Service unter `/platform/profile`. Rate-Limit/Lockout am Login bleiben. Audit `scope=platform` via `writePlatformAudit`. +- **Nicht-destruktiver Richtlinien-Re-Import:** siehe §9 Punkt 2. +- **Benutzer- & Rollenverwaltung (ohne E-Mail-Flow):** + - Plattform-Admin je Mandant: `src/server/actions/platform-users.ts` + `components/platform-tenant-users.tsx`, eingebettet in `/admin/[id]`. Anlegen mit **Initial-/Einmal-Passwort** (selbst setzen oder generiert, einmalig angezeigt), Rollen, Deaktivieren/Reaktivieren, Passwort-Reset. + - Mandanten-Admin intern: `src/server/actions/tenant-users.ts` + `components/tenant-users-manager.tsx`/`role-manager.tsx`, Seite `/settings/users` (nur `user:manage`/`role:manage`). Benutzer-CRUD **und** Rollen-CRUD (eigene Rollen + Permissions; Standardrollen schreibgeschützt/klonbar). Strikt `dbForTenant(session)` → kein Cross-Tenant. **Lockout-Schutz** für den letzten aktiven Mandanten-Admin. + - **Force-Change:** neue Nutzer starten mit `mustChangePassword=true`; das `(app)`-Layout leitet autoritativ (DB) auf `/change-password` und sperrt deaktivierte Konten. Passwort-Policy: `src/lib/password-policy.ts` (Validierung, client-safe) + `src/server/password.ts` (Argon2id-Hash + Generator); Quelle `TenantSettings.securityPolicy.password`. + - **Nutzer-MFA optional:** Tenant-Login (`auth.ts`) verlangt TOTP nur bei eingerichteter MFA; Self-Service unter `/account`. `role:manage` ist neu im RBAC-Katalog (Mandanten-Admin). + - **Bearbeiten:** je Nutzer sind **Name & E-Mail** (E-Mail eindeutig je Mandant), Rollen, Aktiv/Deaktiviert und Passwort-Reset editierbar — in beiden Konsolen. +- **Zuständigkeit Einstellungen (Superadmin vs. Tenant-Admin):** **Kern-Einstellungen** (aktive Module, TISAX-/Schutzbedarf-**Tiefe**, Richtlinienpaket) steuert ausschließlich der **Superadmin** in der Admin-Konsole (`/admin/[id]`, u. a. `setTenantTisaxLevel`). Der **Tenant-Admin** pflegt in `/settings` nur seinen Bereich (Stammdaten/Branding → ISMS-Variablen) + Benutzer/Rollen; die TISAX-Tiefe ist dort nur noch als Read-only-Anzeige. +- **Zukunftssicher:** `createTenantUser`/`createUser` kapseln die Aktivierung über Initial-/Einmal-Passwort — der spätere **E-Mail-Einladungs-Flow (Paket 4)** lässt sich als alternative Aktivierung (Token statt Passwort) einhängen, ohne die UI umzubauen. +- **Benutzer-UI als Popup:** Anlegen/Bearbeiten über URL-gesteuerte Modals (`?new`/`?edit`, generische `components/user-forms.tsx` + `user-table.tsx`) in `/settings/users` und `/admin/[id]`; die Tabelle zeigt nur. +- **Aufgaben-/Freigabe-Modul (`tasks`):** generisches `Task`/`TaskComment` (RLS, in `TENANT_MODELS`). Erster Typ `policy_approval`: beim Einreichen wählt der Autor einen **konkreten Freigeber** (aktiver Nutzer mit `policy:approve`, ≠ Einreicher) → Aufgabe. Freigeben/Ablehnen (mit Grund)/Kommentieren im Bereich **`/tasks`** (nur der zugewiesene Freigeber; Vier-Augen), Verlauf historisiert; **Dashboard-Kachel** zählt offene Freigaben. Actions: `server/actions/tasks.ts` (+ `submitForApproval` in `policies.ts`). Der Editor zeigt nur noch Status/Freigeber + Link zur Aufgabe. +- **Richtlinien-Governance zentralisiert:** zentrale Variablen (Organisation/Rollen/Schutzbedarf-Flags, `lib/policy-variables.ts`) sind im Editor gesperrt (nur Einstellungen); **Schutzbedarf/TISAX** ausschließlich Superadmin (kein Per-Doc-Override, kein globaler Schalter im Modul); **Coverage-Matrix** filtert nach aktivem Assessment-Level (AL2 ohne „sehr hoch"). + +## 11. Nächste sinnvolle Aufgaben (Einstiegspunkte) + +- **SMTP + Einladungs-/Aktivierungs-/Reset-Flow (Paket 4, M):** transaktionale Mails (Nodemailer), signierte Einladungs-/Reset-Tokens; ersetzt/ergänzt den Initial-Passwort-Weg. +- **Admin Phase 2 — Impersonation (M):** neues Modell `ImpersonationSession`, Cookie-basierter effektiver Tenant + Banner, Ablauf, Audit. +- **Tenant-weite MFA-Pflicht scharfschalten (S):** `securityPolicy.mfaRequired` wird von `disableOwnMfa` bereits respektiert; Enrollment-Erzwingung analog zum Force-Change-Gate (Seite außerhalb der `(app)`-Shell) nachziehen. +- **NIS2-Modul (L):** eigenes Modul inkl. Incident-Reporting mit Fristen-Timern. +- **Richtlinien-Versionierung/Diff (M–L)** und **DOCX/PDF-Export (M)**. + +Weitere Details, Priorisierung und Aufwände: **`docs/HANDOVER-PM.md`**. Projekt-Spec: **`docs/SPEC.md`** + Modul-Prompts/Mockups. diff --git a/docs/HANDOVER-DEVOPS.md b/docs/HANDOVER-DEVOPS.md new file mode 100644 index 0000000..a8a4e69 --- /dev/null +++ b/docs/HANDOVER-DEVOPS.md @@ -0,0 +1,122 @@ +# DevOps-Übergabe — ISMS-Tool (Deployment Test → Produktiv) + +> Stand: 2026-07-20 · Branch `main` · Commit `081c000` +> Zweck: Betrieb/Deployment. Gemeinsame Arbeit an Dockerfile, Einrichtung Testserver (remote), danach Produktivserver. +> Ergänzt: `docs/HANDOVER-DEV.md` (App-Architektur/Setup) und `docs/HANDOVER-PM.md` (fachlicher Status). + +--- + +## 1. Überblick der Runtime + +Die App ist eine **Next.js-16-Anwendung im Standalone-Modus** (`output: "standalone"` in `next.config`, Start via `node server.js`), zustandslos horizontal skalierbar. Zustand liegt ausschließlich in den Backing-Services. + +| Service | Image / Herkunft | Port | Zweck | Persistenz | +|--------|------------------|------|-------|-----------| +| **app** | Multi-Stage-Build (`Dockerfile`) | 3000 | Web-App (Next.js standalone) | zustandslos | +| **postgres** | `pgvector/pgvector:0.8.0-pg16` | 5432 | Primärdatenbank (inkl. `vector`-Extension) | Volume `pgdata` | +| **redis** | `redis:7.4.2-alpine` (mit `requirepass`) | 6379 | Cache/Queue (für späteren BullMQ-Worker) | Volume `redisdata` | +| **minio** | `minio/minio:RELEASE.2025-04-22T22-12-26Z` | 9000/9001 | Objektspeicher (noch **ungenutzt**; für kommenden Logo-/Datei-Upload) | Volume `miniodata` | +| **mailhog** | `mailhog/mailhog:v1.0.1` (Profil `dev`) | 1025/8025 | SMTP-Fang für Entwicklung | — | +| **worker** | s. Dockerfile (Profil `worker`) | — | **noch nicht lauffähig** (kein `worker`-npm-Script vorhanden) | — | + +Alles bereits als **`docker-compose.yml`** im Repo-Root beschrieben; **`Dockerfile`** ist ein 4-Stage-Build (`deps` mit `npm ci` → `builder` mit `prisma generate` + `next build` → schlanke `migrate`-Stage für den Migrations-/Seed-Job → schlanker `runner` als non-root `app`-User). Alle Images sind auf konkrete Tags gepinnt (F-11), Base ist `node:22-slim` (glibc). + +--- + +## 2. Umgebungsvariablen (`.env`) + +Vorlage: **`.env.example`**. Vollständige Liste: + +| Variable | Zweck | Prod-Hinweis | +|----------|-------|-------------| +| `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB` | Compose-Init von Postgres | **Secret** (Passwort) | +| `DATABASE_URL` | Prisma-Verbindungsstring | **Secret**; muss auf denselben DB-Nutzer/-Namen zeigen | +| `REDIS_URL` | Redis-Verbindung | — | +| `AUTH_SECRET` | NextAuth-Signaturschlüssel (JWT) | **Secret**, zwingend gesetzt & stark | +| `AUTH_URL` | Öffentliche Basis-URL der App | pro Umgebung (Test/Prod) unterschiedlich, inkl. `https://` | +| `AI_PROVIDER` / `AI_API_KEY` | KI-Chat / KI-Formulierungshilfe (noch ungenutzt) | Secret, optional | +| `SMTP_HOST/PORT/USER/PASSWORD/FROM` | E-Mail (noch ungenutzt; Einladungs-/Benachrichtigungsflow offen) | Secret, optional | +| `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` | Objektspeicher | **fehlen in `.env.example`** → für Prod ergänzen (sonst Compose-Defaults `isms`/`isms-secret`) | + +> **Secrets** gehören nicht ins Git. Für Prod: Secret-Management (Docker Secrets / Env aus Vault / CI-Variablen). `.env.example` enthält nur Namen/Defaults. + +--- + +## 3. Build & Start + +```bash +# Image bauen +docker compose build app + +# Test/lokal hochfahren (ohne dev-only mailhog) +docker compose up -d postgres redis minio app + +# mit Mailhog (Dev): docker compose --profile dev up -d +# Worker (aktuell NICHT lauffähig, s. §6): docker compose --profile worker up -d worker +``` + +App danach unter `AUTH_URL` (Port 3000) erreichbar. + +--- + +## 4. ⚠️ Datenbank-Migrationen & Bootstrap (kritisch) + +**Der App-Container führt KEINE Migrationen beim Start aus** (CMD ist `node server.js`). Migrationen und das erste Provisioning sind ein **separater Deploy-Schritt**: + +1. **Migrationen anwenden:** `npx prisma migrate deploy` gegen die Ziel-DB. + - Die `runner`-Stage enthält Prisma-CLI/`tsx` **nicht** (nur Runtime-Trace). Migrationen daher aus der **`builder`-Stage** (voller `node_modules`) oder aus einem eigenen **Migrations-Job/CI-Step** fahren. → **Designentscheidung mit DevOps** (z. B. Init-Container `command: npx prisma migrate deploy` mit builder-Image, `restart: "no"`). + - Die Init-Migration legt `CREATE EXTENSION IF NOT EXISTS "vector"` an (pgvector) — das Postgres-Image bringt die Extension mit. +2. **Erster Mandant / Superadmin (Prod):** Der Demo-Seed (`prisma/seed.ts`) ist **nur für Entwicklung** (Demo-Mandant + Testnutzer) — **nicht in Produktion ausführen**. In Prod erfolgt das Anlegen von Kunden über die **Admin-Konsole** (`provisionTenant`). **Offen:** Es gibt aktuell **kein Bootstrap-Skript** für den allerersten Plattform-Admin — dieser muss initial angelegt werden (Skript/One-Off gegen `provisionTenant` mit `isPlatformAdmin: true`, oder manuell). → **Mit App-Entwickler abstimmen** (kleiner Task). + +--- + +## 5. Persistenz, Backup & Restore + +- **Volumes:** `pgdata` (kritisch), `miniodata` (künftig Uploads), `redisdata` (unkritisch, Cache). +- **Backups Prod:** regelmäßiger `pg_dump` (logisch) oder Volume-/Snapshot-Backup; MinIO-Bucket-Backup, sobald Uploads aktiv. Aufbewahrung + Restore-Test einplanen (DSGVO-Löschkonzept ist app-seitig noch offen). +- Mandantentrennung ist **logisch** (eine DB, `tenant_id` + Postgres-RLS + App-Guard) — Backups umfassen alle Mandanten gemeinsam. + +--- + +## 6. Bekannte Lücken / To-dos für DevOps + +1. **`worker`-Service nicht lauffähig:** Es existiert **kein `npm run worker`**-Script (BullMQ-Scheduler ist app-seitig noch nicht implementiert). Profil `worker` bis dahin **nicht** starten. +2. **Migrations-/Bootstrap-Strategie** festlegen (§4) — Migrations-Job + Erst-Superadmin. +3. **MinIO-Env** in `.env` für Prod ergänzen; MinIO wird erst mit dem kommenden Logo-/Datei-Upload wirklich genutzt (Bucket-Präfix je Mandant vorgesehen). +4. **Reverse-Proxy + TLS** vor der App (Port 3000 nicht direkt exponieren): Traefik/Caddy/nginx mit HTTPS; `AUTH_URL` auf die öffentliche `https://`-Adresse setzen. Rate-Limiting/IP-Härtung für Login/Admin einplanen. +5. **Ressourcen/Skalierung:** `app` ist zustandslos → mehrere Replicas möglich; Sticky-Sessions nicht nötig (JWT). Postgres/Redis als Singleton bzw. Managed-Service. +6. **Health/Observability:** Postgres-Healthcheck vorhanden; für `app` einen HTTP-Healthcheck/Readiness ergänzen (derzeit keiner definiert). Log-Aggregation + Alerting einrichten. +7. **`AUTH_SECRET`** je Umgebung eindeutig & stark; bei Rotation invalidieren alle Sessions. + +--- + +## 7. Test- vs. Produktivumgebung — Unterschiede + +| Aspekt | Test (Remote) | Produktiv | +|--------|---------------|-----------| +| Daten | ggf. Demo-Seed erlaubt | **kein Demo-Seed**; nur echtes Provisioning | +| Secrets | Test-Werte | echte Secrets aus Secret-Store | +| Mail | Mailhog (Profil `dev`) | echtes SMTP-Relay | +| TLS | optional/self-signed | verpflichtend, gültiges Zertifikat | +| Backups | optional | verpflichtend + Restore-Test | +| Skalierung | 1 Replica | ≥ 2 App-Replicas hinter Proxy | + +--- + +## 8. Deploy-Checkliste (Kurz) + +**Testserver:** +1. Repo klonen/pullen (Gitea, Branch `main`). +2. `.env` aus `.env.example` mit Test-Werten (inkl. `MINIO_*`). +3. `docker compose build app`. +4. `docker compose up -d postgres redis minio`. +5. **Migrationen:** `prisma migrate deploy` (builder-Image/Job). +6. **Erst-Superadmin** anlegen (One-Off, s. §4) — für Test ggf. Demo-Seed ok. +7. `docker compose up -d app`; Reverse-Proxy/TLS davor; Smoke-Test (Login, Admin-Konsole, Modul-Seite). + +**Produktivserver:** wie oben, aber Secret-Store, **kein** Demo-Seed, TLS verpflichtend, Backups + Monitoring aktiv, ≥ 2 App-Replicas, Migrations-/Bootstrap-Schritt in die Deploy-Pipeline integriert. + +--- + +## 9. Referenzen im Repo +`Dockerfile`, `docker-compose.yml`, `.env.example`, `next.config.*` (`output: standalone`), `prisma/schema.prisma` + `prisma/migrations/**` (inkl. RLS-Policies & pgvector), `prisma/seed.ts` (nur Dev), `src/server/provision.ts` (Provisioning-Logik für Prod-Onboarding). diff --git a/docs/HANDOVER-PM.md b/docs/HANDOVER-PM.md new file mode 100644 index 0000000..57e9bab --- /dev/null +++ b/docs/HANDOVER-PM.md @@ -0,0 +1,98 @@ +# Projektübergabe — ISMS-Tool (Stand für Projektmanagement) + +> 📌 **Konsolidierter Gesamtstand aller Entwicklungstätigkeiten auf `dev` (PM + Dev):** siehe **`docs/STAND-dev-branch.md`**. + +> Stand: 2026-07-22 · Branch `dev` (Produktionshärtung + Benutzerverwaltung; noch nicht nach `main` gemerged) +> Zweck: Statusüberblick für die Weiterplanung — was ist umgesetzt, was ist offen (mit Priorität & grobem Aufwand). + +## 🆕 Neu auf `dev` (Produktionshärtung Phase 1 + Benutzerverwaltung) + +| Thema | Status | Kurz | +|-------|:------:|------| +| **API-seitige Modul-Durchsetzung** | ✅ | Deaktiviertes Modul sperrt jetzt auch Writes serverseitig; automatischer Vollständigkeitscheck (Build-Gate). | +| **Separater Superadmin-Store + eigener Login** | ✅ | Eigener Store/Login (`/platform/login`), Session ohne Mandantenbezug; `isPlatformAdmin`-Umweg abgelöst. | +| **MFA für Superadmins** | ✅ (optional) | Zunächst als Pflicht gebaut, dann auf **optional** umgestellt; Policy-Flag „MFA-Pflicht" (aus) stellt die Erzwingung wieder her. | +| **Nicht-destruktiver Richtlinien-Re-Import** | ✅ | Diff/Upsert; Status/Override/Freigabe/Variablenwerte bleiben, entfernte Einträge werden deaktiviert; Änderungsreport + Vorschau. | +| **Benutzer- & Rollenverwaltung** | ✅ | Plattform-Admin legt je Kunde Nutzer an (Initial-/Einmal-Passwort); Mandanten-Admin verwaltet Nutzer **und** Rollen intern (eigene Rollen + Rechte, Standardrollen klonbar), mandantengetrennt + Lockout-Schutz. Force-Change beim ersten Login, Passwort-Policy. | +| **Nutzer-MFA (Mandant)** | ✅ (optional) | Je Nutzer aktivierbar (`/account`); Login verlangt Code nur bei aktiver MFA. | +| **SMTP + Einladungs-/Aktivierungs-/Reset-Flow (Paket 4)** | ⏸️ zurückgestellt | E-Mail-Versand bewusst später; die Nutzer-Aktivierung läuft vorerst über Initial-/Einmal-Passwort und ist so gekapselt, dass der Einladungs-Flow ohne Umbau ergänzt werden kann. | + +## Was ist das Produkt + +Multi-Tenant-**SaaS für Informationssicherheits-Management (ISMS)**, ausgerichtet auf **ISO/IEC 27001:2022** und **TISAX / VDA-ISA 2027**. Web-App (Deutsch, EN vorbereitet), Dark-Theme, mandantenfähig (mehrere Kunden, Nutzer, Rollen). Mehrere fachliche Module + Plattform-/Kundenverwaltung. + +**Aufwands-Legende:** **S** = klein (≤ 1 Tag) · **M** = mittel (2–4 Tage) · **L** = groß (> 1 Woche). + +--- + +## ✅ Umgesetzt (produktiv nutzbar) + +| # | Modul | Umfang (Kurz) | +|---|-------|---------------| +| 1 | **Fundament** | Login/Auth (lokale Accounts, NextAuth v5, JWT), **RBAC** (granulare Rechte, Rollen je Mandant), **Mandanten-Isolation** (tenant_id + Postgres-RLS + zentraler App-Guard), i18n (de/en), Dark-Theme (zentrale Tokens), Audit-Log. | +| 2 | **Assets & BIA** | Asset-Inventar + Geschäftsprozesse/BIA als ein Modul; C/I/A-Schutzbedarf, Vererbung, Abhängigkeiten; Detail/Bearbeiten/Anlegen als Popups; zugeordnete Risiken. | +| 3 | **Risikoanalyse** | 5×5-Heatmap, Risikoregister, Risiko-Detail mit Maßnahmen (dezimale Minderung, Brutto→Rest visualisiert), Bedrohungs-/Schwachstellen-Kataloge, Control-Verknüpfung. | +| 4 | **Maßnahmen** | Kanban-Board (Drag & Drop), berechnetes Restrisiko aus Maßnahmen. | +| 5 | **Abhängigkeiten & kritische Pfade** | Interaktiver Graph (React Flow + dagre), Single Points of Failure, kritische Pfade. | +| 6 | **Lieferanten- & IT-Service-Management** | Asset-basiert (Lieferant/IT-Service **sind** Assets); Anforderungs-Engine (Schutzbedarf→Stufen), Gate-Logik (erzeugt echte Risiken), ISB-Reifegrad-Freigabe; **RACI-Matrix** über ISA-Controls (VDA-ISA 6.1.3); Cockpit direkt aus dem Asset-Inventar öffenbar. | +| 7 | **Richtlinien & Verfahren (VDA-ISA 2027)** | Siehe Detailblock unten — größtes Modul. | +| 8 | **Admin-Konsole & Mandantenverwaltung (Phase 1)** | Plattform-Admin (`/admin`): Kunden anlegen + **automatisch provisionieren**, Module-Toggles, Lebenszyklus (aktiv/gesperrt/archiviert). Kunden-Einstellungen (`/settings`): Stammdaten → speisen ISMS-Variablen, Branding, TISAX-Level. **Serverseitige Modul-Durchsetzung** (deaktivierte Module gesperrt, nicht nur ausgeblendet). | + +### Modul 7 „Richtlinien & Verfahren" im Detail (umgesetzt) +- **Import** des VDA-ISA-2027-Vorlagenpakets: **28 Dokumente** (Leitlinie L00, R01–R14, VA-01–VA-13), **316 Anforderungen** (122 MUSS · 132 SOLL · 43 HOHER · 19 SEHR HOHER Schutzbedarf) über **45 Controls**; Baseline-Parameter, Variablen, Nachweisregister. +- **Rendering-Engine**: Handlebars (verschachtelte `{{#if}}`-Flags), Variablen aus einer Pflegestelle, Deep-Links, BL-Referenzen im Lesemodus entfernt; rückstandsfrei über alle Flag-Kombinationen. +- **Bibliothek** + **Referenz-/Coverage-Matrix** (zwei Richtungen: nach Control / nach Dokument). +- **Lesemodus** als eigene Seite (kein Popup); **Bearbeitungsmodus** variablenbasiert + **Vier-Augen-Freigabe** (Entwurf → In Freigabe → Freigegeben); **Experten-Modus** (Rohtext-Editor + Formatier-/Einfügehilfen + Auto-Anlage neuer Variablen). +- **Verwaltete Register** (editierbar): Verschlüsselungsregister (mit Ablaufüberwachung), Risiko-Bewertungsmatrix (FB-80-04-Defaults), Klassifizierungs-Handhabungsmatrix (AA-80-20). **Anwender-Handbuch** (kuratiert, Baseline-synchron, Deep-Links). +- **Schutzbedarf-/TISAX-Level-Schalter (AL2/AL3)** global + **Override je Richtlinie**. + +--- + +## 🟥 Offen — Hohe Priorität + +| Thema | Aufwand | Anmerkung | +|-------|:------:|-----------| +| **NIS2-Modul** (nie begonnen) | **L** | Framework Art. 20/21 + Control-Mapping, Einrichtungs-Einstufung + BSI-Registrierung, **Incident-Reporting-Workflow mit Fristen-Timern (24 h / 72 h / 1 Monat)**, NIS2-Dashboard. War „Teil C" der ursprünglichen Planung. | +| **Admin-Konsole Phase 2 — Impersonation** | **M** | Zeitlich begrenzter, protokollierter Support-Zugriff in einen Mandanten; „Support-Sitzung aktiv"-Banner; automatischer Ablauf. | +| **Admin-Konsole Phase 2 — Plan/Limits** | **M** | Lizenzstufen, Limits (Nutzer/Speicher/Assets), Warnung/Sperre bei Überschreitung. | +| **Separater Superadmin-Store + eigener Login + MFA-Pflicht** | **M–L** | Aktuell ist der Superadmin ein `isPlatformAdmin`-Nutzer im Mandanten (Demo). Spec fordert getrennte Accounts + eigenen Login-Pfad. | +| **Richtlinien: echte Versionierung + Diff** | **M–L** | Aktuell ändert die Freigabe nur den Status (ohne Versionshistorie/Diff). Entwurf-neben-Freigegeben, block-/klauselgenauer Diff. | +| **Richtlinien: DOCX/PDF-Export** | **M** | Voll gerendert im GEFIM-Corporate-Design; Referenz-/Nachweisdoku separat. | + +--- + +## 🟧 Offen — Mittlere Priorität + +| Thema | Aufwand | Anmerkung | +|-------|:------:|-----------| +| **Richtlinien: Status „Revoked" + Auto-Version** | **S** | Vom Kunden ausdrücklich für später gemerkt: Status-Auswahl inkl. Revoked (manuell), Version zählt bei jedem Speichern automatisch hoch. | +| **Richtlinien: Word-Upload (.docx-Import)** | **M** | Eigene Dokumente hochladen → Block-Modell + Original als Anhang, versioniert, im Freigabeprozess. | +| **Richtlinien: KI-Wizard** | **L** | Geführte Erstellung/Anpassung (control-getrieben, Feature-Flags/Reifegrad), KI formuliert Blocktext. | +| **Richtlinien: KI-Formulierungshilfe im Experten-Modus** | **M** | Braucht Anthropic-API-Anbindung. | +| **Zentrale Baseline-/Variablen-Einstellseite** | **S–M** | Eine Pflegestelle mit Freigabe-Durchlauf. | +| **Admin Phase 2 — Logo-Upload / Objektspeicher je Mandant** | **M** | Für UI-Kopf + Export (Branding/Whitelabel). | +| **Admin Phase 2 — SMTP/Benachrichtigungen + Einladungs-/Aktivierungs-Flow** | **M** | E-Mail-Einladung, Passwort-Setzen, Benachrichtigungsregeln (Fristen/Freigaben/Vorfälle). | +| **Lieferanten Phase 2** | **M–L** | Fragebogen-Builder, Self-Service-Portal (externer Lieferantenzugang), Scheduler (Review-/Ablauf-Erinnerungen). | +| **Risikomatrix zusammenführen** | **M** | Bewertungsmatrix im Richtlinienmodul ist eigene 4×4-Pflegestelle (FB-80-04); Risikoanalyse nutzt 5×5. Auf eine gemeinsame, zentrale Skala vereinheitlichen. | +| **Platzhalter-Module ausbauen** | je **M–L** | Sidebar-Punkte vorhanden, aber nicht gebaut: **SoA & Controls**, **Vorfälle**, **Nachweise**, **Management-Review**, **KI-Chat**. | + +--- + +## 🟩 Offen — Niedrige Priorität / Technische Schulden + +| Thema | Aufwand | Anmerkung | +|-------|:------:|-----------| +| **Modul-Durchsetzung auf API-Ebene vervollständigen** | **S** | Route-Zugriff (GET) ist für alle Module gesperrt; der `requireModule`-Guard in Server-Actions ist bisher **exemplarisch nur für Richtlinien** gesetzt. Einzeiler je Action-Guard nachziehen. | +| **Richtlinien-Re-Import ist destruktiv** | **M** | Re-Import löscht + legt Dokumente/Anforderungen neu an (setzt per-Dokument-Status/Override/Freigabe zurück). Spec wünscht „deaktivieren statt löschen" + Historie erhalten. | +| **Coverage zeigt alle statt nur aktive Anforderungen** | **S** | Referenzmatrix listet vollständig (gut für Audit); optional Filter „nur aktive" nach effektiven Flags. | +| **Admin Phase 2 — Datenexport/Löschung/Retention (DSGVO)** | **L** | Mandantenvollständiger Export, Löschkonzept, Aufbewahrungsfristen. | +| **Optionale Zusatzfeatures** | je **M** | SSO (OIDC/SAML), API-Keys/Webhooks, Onboarding-Wizard, E-Mail-Domain-Allowlist, Wartungs-/Status-Banner. | + +--- + +## Hinweise für die Planung + +- **Spezifikationen** liegen im Repo: `docs/SPEC.md` (Gesamt-Spec) sowie die Übergabe-Prompts und Mockups je Modul (Richtlinien, Admin-Konsole). Neue Anforderungen kamen bisher als „Delta-Prompts" (z. B. TISAX-Level-Update). +- **Nächster logischer Block:** entweder **NIS2** (letztes großes Framework, hängt am Incident-/Vorfälle-Modul) oder **Admin-Konsole Phase 2** (Impersonation + Plan/Limits + Superadmin-Login), je nach Vertriebs-/Compliance-Priorität. +- **Demo-Umgebung:** Mandant „demo", Login `admin@demo.example` (ist Superadmin + Mandanten-Admin), Passwort im Seed. 4 Demo-Rollen vorhanden. +- **Qualität:** Jede Iteration wurde mit `tsc` + `lint` + `build` und – wo möglich – Browser-Verifikation abgeschlossen; Commits sind fein granular und je Thema. diff --git a/docs/IMPL-tisax-wizard-neustruktur.md b/docs/IMPL-tisax-wizard-neustruktur.md new file mode 100644 index 0000000..002eac2 --- /dev/null +++ b/docs/IMPL-tisax-wizard-neustruktur.md @@ -0,0 +1,238 @@ +# Implementierungsfaden — TISAX-Onboarding-Wizard Neustruktur + +> Status: Entwurf · Grundlage: Konzept v2 (4 Ebenen, nach TISAX-Fachprüfung) + IST-Analyse des Task-Moduls (Branch `dev-tasks-kanban`, `ce1e847`). +> Ziel: Aus dem linearen 9-Schritt-Monolithen `/onboarding` werden vier Ebenen — **Fundament → Strukturanalyse → Cockpit → Audit** — informationszentriert, prozessgeführt erhoben, bereichsbasiert umgesetzt. + +--- + +## 0. Ausgangslage & Auswirkung der Kanban-Anpassung + +Das Task-Modul wurde zwischenzeitlich auf ein **Kanban-Board** umgestellt (`src/components/kanban-board.tsx`, `src/app/(app)/tasks/page.tsx`, Action `updateTaskStatus`, Status `IN_PROGRESS`). Das ist die Basis für Ebene 3 — das Bereichs-Board wird **additiv** darauf gebaut, nicht neu. + +**Bereits vorhanden (nutzbar):** generisches Task-Modell, Kanban mit DnD-Statuswechsel, `assigneeId` + `createdById` + Vier-Augen-Freigabe, PROPOSED→OPEN/DISCARDED-Vorschlagsmechanik, Wizard-Trigger (`task-triggers.ts`, `proposeTasksFromTriggers`), polymorphe `links`-Json + harte `entityType/entityId`-Kopplung, Teil-Sync Task→Objekt bei Policy-Freigabe (`approveTask`). + +**Fehlt (dieser Plan liefert es):** `domain`/Bereich, RACI/Mitwirkende, `orderIdx`, Recurrence/Wiedervorlage, Auto-Completion-Deckel, Bereichs-/Personen-Filter, harte Control-/Evidence-Verknüpfung, Information als Kernobjekt. + +**Altlasten (Vorarbeit M0):** +- `TASK_STATUSES` in `src/lib/tasks.ts` enthält `IN_PROGRESS` nicht, obwohl Board/Actions ihn nutzen → Inkonsistenz beheben. +- `src/app/(app)/tasks/page.tsx:166` referenziert `open` — im File nicht definiert (nur `myOpen`/`active`/`proposals`/`terminal`). Verifizieren & fixen. + +--- + +## 1. Datenmodell (Prisma-Migrationen) + +Konventionen wie im Bestand: `cuid()`-IDs, `tenantId`, `@@map(snake_case)`, `@@unique([tenantId, …])`. Enums additiv; freie `String`-Statusfelder brauchen keine Migration. + +### 1.1 Werte-Modell: Information IST ein (primärer) Asset — kein Extra-Objekt + +**Korrektur ggü. erstem Entwurf.** Ein Informationswert ist kein neues Objekt neben dem Asset, sondern ein **primärer Asset** (ISO 27005 / TISAX: primäre Werte = Informationen + Prozesse; sekundäre = Träger). Euer Schema bildet das bereits ab: +- `AssetType.INFORMATION` / `DATA` = primäre Werte; `SYSTEM/APPLICATION/LOCATION/SUPPLIER/IT_SERVICE/SOFTWARE/PERSON` = sekundär/Träger. +- `ProcessAsset.role = PRIMARY | SECONDARY` trennt primär/sekundär je Prozess-Beziehung. +- `AssetRelation` bildet Träger-Abhängigkeiten ab; `confidentiality/integrity/availability` liegen schon am `Asset`. + +→ **Kein** `InformationValue`/`ProcessInformation`/`InformationAsset`. Stattdessen kleine Ergänzungen am Bestand: + +```prisma +enum InfoLabel { NONE INFO_HIGH INFO_VERY_HIGH PROTOTYPE PERSONAL_DATA } + +model Asset { + // … Bestand (type, C/I/A, ownerId, status, tags) … + normalizedName String? // Dedup-Schlüssel (s. 2.1) + label InfoLabel @default(NONE) // Info hoch/sehr hoch, Prototyp, personenbezogen → steuert Scope/Bereiche + @@unique([tenantId, normalizedName]) // verhindert Exakt-Duplikate (v.a. type INFORMATION/DATA) +} +``` + +**Primär/sekundär** bleibt über `ProcessAsset.role`. Optional als intrinsische Klassifikation `Asset.tier (PRIMARY|SUPPORTING)`, ableitbar aus `type` — nur einführen, falls die Rolle je Prozess nicht ausreicht (s. offene Entscheidung 4.1). +**Schutzbedarf:** bleibt am `Asset`. Primäre Informations-Assets tragen den echten C/I/A-Wert; sekundäre erben per **Maximum** der von ihnen getragenen primären Assets. +**„Erhebung über den Prozess":** Im Prozess-Schritt werden primäre Informations-Assets erfasst (Dedup/Autocomplete gegen bestehende Assets, 2.1), dann Träger-Assets via `ProcessAsset(SECONDARY)` + `AssetRelation` verknüpft. Anker = das primäre Informations-Asset. **Keine Datenmigration nötig** — nur additive Spalten. + +### 1.2 Standard-Prozess-Katalog (Ebene 2) + +```prisma +model ProcessCatalogEntry { // global, kein tenantId + id String @id @default(cuid()) + code String @unique + name String + category ProcessCategory // CORE | MANAGEMENT | SUPPORT (Neben→SUPPORT) + suggestedAssetTypes AssetType[] + suggestedRiskCodes String[] // → RiskCatalogEntry.code + suggestedInfoLabels InfoLabel[] + @@map("process_catalog") +} +``` + +### 1.3 Team / Funktionszuordnung (Ebene 1) + +Heute sind ISMS-Rollen read-only Variablen. Neu: echte Zuordnung Funktion→User(n) inkl. „unbesetzt". + +```prisma +model ProjectFunctionAssignment { + id String @id @default(cuid()) + tenantId String + functionKey String // ISB, PM, HR_LEAD, IT_LEAD, BCM, AUDITOR_INT, DPO … + userId String? // null = unbesetzt → erzeugt Task „Funktion besetzen" + domain Domain? // Default-Bereich dieser Funktion (Sichtbarkeit) + invitedEmail String? // Einladung, falls Account noch nicht existiert + createdAt DateTime @default(now()) + @@index([tenantId, functionKey]) + @@map("project_function_assignments") +} +``` + +### 1.4 Bereich (Domain) & Control→RACI-Mapping (Ebene 3) + +```prisma +enum Domain { GOVERNANCE HR PHYSICAL BCM IT PROCUREMENT COMPLIANCE DATA_PROTECTION PROTOTYPE } +enum RaciKind { RESPONSIBLE ACCOUNTABLE CONSULTED INFORMED } + +model ControlDomainMap { // global default; tenant-Override via tenantId + id String @id @default(cuid()) + tenantId String? // null = globaler Default + control String // "3.1.4" oder Kapitel-Präfix "3" + domain Domain + raci RaciKind @default(RESPONSIBLE) + functionKey String? // Default-Verantwortliche Funktion + @@map("control_domain_map") +} +``` + +Seed-Defaults (Kapitel → Bereich), fachlich korrigiert: +| Kapitel | Domain | Anmerkung | +|---|---|---| +| 1 | GOVERNANCE | ISB + Management | +| 2 | HR | | +| 3 (phys.) | PHYSICAL | | +| 3 (BCM) | BCM | **aus K3 gelöst** — eigener Bereich | +| 4 IAM | IT + **HR (CONSULTED)** | Joiner-Mover-Leaver | +| 5 | IT | | +| 6 | PROCUREMENT + **ISB/Recht (CONSULTED)** | | +| 7 | COMPLIANCE + **DPO/IT (CONSULTED)** | | +| Prototyp | PROTOTYPE | nur bei Label | +| Datenschutz | DATA_PROTECTION | nur bei Label | + +### 1.5 Task-Erweiterungen (Ebene 3) + +```prisma +model Task { + // … Bestand … + domain Domain? // Bereich (Default aus ControlDomainMap) + orderIdx Int @default(0) // manuelle Sortierung je Bereich + recurrence String? // ISO-8601-Dauer/RRULE, z.B. "P1Y" + remindAt DateTime? + effectiveUntil DateTime? // Wirksamkeitsintervall (Wiedervorlage) + participants TaskParticipant[] + @@index([tenantId, domain, status]) +} + +model TaskParticipant { // RACI zusätzlich zu assigneeId (=primär Responsible) + id String @id @default(cuid()) + tenantId String + taskId String + userId String + raci RaciKind + @@unique([tenantId, taskId, userId, raci]) + @@map("task_participants") +} +``` + +### 1.6 Nachweis-/Evidence-Register (Ebene 3+4) + +```prisma +model Evidence { + id String @id @default(cuid()) + tenantId String + title String + kind String // record | protocol | screenshot | export + fileRef String? + taskId String? + control String? + validFrom DateTime? + validUntil DateTime? // koppelt an Task.effectiveUntil + createdAt DateTime @default(now()) + @@index([tenantId, control]) + @@map("evidence") +} +``` + +--- + +## 2. Querschnitts-Bausteine + +### 2.1 Dedup-Erkennung & Autovervollständigung für Informationswerte + +Kernanforderung: Menschen erfassen über den Prozess, sollen aber denselben Wert nicht doppelt anlegen (auch nicht bei abweichender Groß-/Kleinschreibung). + +- **Normalisierung → `normalizedName`:** `trim` → Mehrfach-Whitespace kollabieren → Unicode-NFC → `toLowerCase` (locale-aware `de`) → Umlaut-Faltung (ä→ae, ö→oe, ü→ue, ß→ss) → Satzzeichen entfernen. Ergebnis ist der `@@unique`-Schlüssel. + - Beispiel: „Kundendaten", „kundendaten", „ Kunden­daten " → alle `kundendaten`. +- **Exakt-Duplikate:** durch `@@unique([tenantId, normalizedName])` unmöglich; bei Kollision wird das bestehende Asset *verknüpft* (`ProcessAsset`) statt neu angelegt. +- **Autovervollständigung:** As-you-type-Suche im Server (`searchAssets(query)`, gefiltert auf `type INFORMATION/DATA`) gegen (a) das Tenant-Asset-Register und (b) globale Katalog-Vorschläge. Treffer zeigen „bereits erfasst in Prozess X" → ein Klick verknüpft. +- **Fuzzy-Nah-Duplikate (weiche Warnung):** Trigramm-/Levenshtein-Ähnlichkeit auf `normalizedName`; ab Schwelle „Meintest du *Kundendaten*?" **vor** dem Anlegen. Bei Postgres optional `pg_trgm` (`similarity()`), sonst in-app Levenshtein auf der Kandidatenliste. +- **UI:** Combobox (bestehendes `components.json`/shadcn-Setup) mit Vorschlagsliste, Badge „neu" vs. „verknüpfen". + +### 2.2 Auto-Completion-Engine — gedeckelt + +Zentrale Funktion `syncTaskFromObject(entityType, entityId)`, aufgerufen bei Statuswechsel von Policy/Risk/Control/Asset. Fachprüfungs-Regel: **Existenz ≠ Wirksamkeit.** + +| Auslöser | Task geht auf … | Deckel | +|---|---|---| +| `PolicyDocument.status = FREIGEGEBEN` | `DONE` (dokumentiert) | Reifegrad 3 / audit-ready nur mit verknüpftem `Evidence` + Vier-Augen | +| Asset C/I/A + Owner gesetzt | `DONE` | — | +| `Risk.status = ACCEPTED/CLOSED` | `DONE` | Restrisiko gesetzt | +| `ControlImplementation.status = erledigt` | `DONE` (umgesetzt) | Reifegrad-Anhebung getrennt bestätigen | + +- Kein Auto-`DONE` ohne mindestens dokumentierten Zustand; „audit-ready" ist ein **separater, manueller** Schritt mit Nachweis. +- **Wiedervorlage:** Tasks mit `recurrence` erzeugen bei `DONE` automatisch eine Folge-Task mit neuem `dueDate`/`effectiveUntil` (Serienlogik). + +### 2.3 Bereichs-Sichtbarkeit & RACI + +- Default-Sicht: **eigene Bereiche** (aus `ProjectFunctionAssignment.domain` des Users) + eigene/zugewiesene Tasks + Pool. +- **PM + ISB:** `task:read_all` (existiert bereits) → alle Bereiche. +- Gezielte Mitwirkung: Eintrag in `TaskParticipant` (CONSULTED/INFORMED) macht Task für die Person sichtbar, ohne ihr den ganzen Bereich zu öffnen. +- Kanban erhält einen **Bereichs-Selektor** (Lane-Filter) zusätzlich zu den Status-Spalten; Sortierung je Bereich nach `orderIdx`, dann Priorität. + +--- + +## 3. Meilenstein-Faden (jeder Schritt einzeln lauffähig) + +### M0 · Vorarbeit & Bereinigung +- `TASK_STATUSES` um `IN_PROGRESS` ergänzen (`src/lib/tasks.ts`); `open`-Bug in `tasks/page.tsx:166` verifizieren/fixen. +- Enums `Domain`, `RaciKind`, `InfoLabel`, `InfoProcessRole` + Task-Felder `domain`/`orderIdx` (nullable) migrieren — noch ohne UI-Wirkung. +- *Risiko: minimal. Kein Verhaltensbruch.* + +### M1 · Ebene 1 „Fundament" (Wizard-Umbau Teil 1) +- Onboarding-Steps in `src/lib/onboarding/register-steps.ts` neu ordnen/ergänzen: `context` → `scope` (einfrieren) → `policy` (Leitlinie, verlinkt Richtlinien-Modul) → `roles`(Team) → `criteria` (Risikoakzeptanz + C/I/A-Skala). +- **Team-Entität** `ProjectFunctionAssignment` + Zuweisen/Einladen-Flow (Schritt `roles`). Neue Funktionen: BCM, unabhängiger interner Auditor, DPO, Asset-/Risk-Owner-Kennzeichnung. +- Leitlinie als Fundament-Artefakt (nicht als Cockpit-Task). +- *Betroffen: `src/app/(app)/onboarding/steps/*`, `src/server/roles.ts`, `src/server/actions/onboarding*.ts`.* + +### M2 · Ebene 2 „Strukturanalyse" (Information = primärer Asset) +- Additive `Asset`-Spalten (`normalizedName`, `label`) + `ProcessCatalogEntry` migrieren. **Keine** Datenmigration — Bestand bleibt gültig. +- Wizard-Fluss **prozessgeführt**: Prozesse wählen (Katalog) → je Prozess primäre Informations-Assets erfassen (Combobox mit Dedup/Autocomplete, 2.1) → Träger-Assets (`ProcessAsset SECONDARY`: System/Anwendung/Raum/Person/Dienstleister/Standort) → Schutzbedarf am Asset (Maximum/Kumulation/Verteilung) → Risiken aus Katalog. +- *Betroffen: neue Steps `processes`/`assets`/`protection`/`risks`, `RiskCatalogEntry`-Matching (existiert).* + +### M3 · Ebene 3 „Cockpit" auf bestehendem Kanban +- `ControlDomainMap` seeden (Tabelle 1.4); Task-Erzeugung (`soa.ts`, `task-triggers.ts`, `gap.ts`) setzt `domain` + Default-RACI. +- Kanban erweitern: Bereichs-Lane/-Filter + Personen-Filter; Default „meine Bereiche"; `orderIdx`-Sortierung (DnD persistiert Reihenfolge). +- `TaskParticipant` (RACI) + Sichtbarkeitslogik (2.3). +- **Auto-Completion-Engine** (2.2) + Recurrence/Wiedervorlage; `Evidence`-Register. +- Fragebogen (`context`) auf Bereiche verteilen → Fragen erzeugen Tasks im jeweiligen Bereich. +- *Betroffen: `kanban-board.tsx`, `tasks/page.tsx`, `src/server/actions/tasks.ts`, `soa.ts`, `policies.ts` (Sync-Hook).* + +### M4 · Ebene 4 „Audit-Wizard" abtrennen +- Neuer, aktivierbarer Wizard aus heutigen Steps `gap` + `readiness`; **internes Audit** (unabhängig, AL3-Pflicht) als eigener Schritt ≠ Readiness-Snapshot. +- Reifegrad + Nachweise laufen bereits kontinuierlich (M3) → hier nur Konsolidierung + Management-Review. +- *Betroffen: neue Route `/audit-readiness` o. ä., Auslagern aus `onboarding/register-steps.ts`.* + +--- + +## 4. Offene Entscheidungen +1. **Primär/sekundär — intrinsisch oder relational?** Reicht `ProcessAsset.role` (Rolle je Prozess), oder soll ein intrinsisches `Asset.tier (PRIMARY|SUPPORTING)` als Wahrheit ergänzt werden (ableitbar aus `type`)? → Vorschlag: mit `role` starten, `tier` nur bei Bedarf. *(C/I/A-Ablageort ist entschieden: bleibt am `Asset`, sekundär erbt per Maximum.)* +2. **Fuzzy-Matching-Technik:** `pg_trgm` (DB-nah, schnell) vs. in-app Levenshtein (DB-agnostisch). → Abhängig davon, ob Postgres-Extension im Coolify-Deployment verfügbar ist. +3. **RACI-Tiefe:** volle RACI oder zunächst nur Responsible + Consulted (Sichtbarkeit)? → Vorschlag: klein starten (R + C), A = ISB/PM implizit. +4. **Audit-Wizard-Aktivierung:** manuell vs. ab Coverage-Schwelle. + +--- + +## 5. Reihenfolge-Logik (warum dieser Faden) +M0 legt risikolos das Datenfundament. M1–M2 bauen die *sequenziellen* Ebenen (Setup/Strukturanalyse), auf denen alles Weitere aufsetzt — inkl. der informationszentrierten Struktur, dem größten Modell-Hebel. M3 nutzt maximal das bereits vorhandene Kanban (additiv statt Neubau). M4 ist die saubere Abtrennung am Ende. Jeder Meilenstein ist für sich lauffähig und liefert sichtbaren Nutzen. diff --git a/docs/ISMS-Abhaengigkeitskarte-GEFIM.html b/docs/ISMS-Abhaengigkeitskarte-GEFIM.html new file mode 100644 index 0000000..49c1b0b --- /dev/null +++ b/docs/ISMS-Abhaengigkeitskarte-GEFIM.html @@ -0,0 +1,244 @@ + + + + + +GEFIM ISMS – Abhängigkeitskarte + + + + + + +
+
+
+ GEFIM +
+
Abhängigkeiten & kritische Pfade
+
Prozess „Auftragsabwicklung" · Asset-Verkettung
+
+
+
+ + + + + +
+
+ +
+
+
+
+ +
+
+
+
↔ horizontal scrollbar · Knoten anklicken hebt den zugehörigen Pfad hervor · Icons zeigen den Asset-Typ
+ +
+
Kritischer Pfad
+
Standard-Abhängigkeit
+
Betriebsbereit
+
PrimärErgebnis-Asset
+
SPOFSingle Point of Failure
+
+ +
+
+
SPOFEngstelle erkannt
+

Active Directory trägt 3 kritische Prozesse. Ein Ausfall unterbricht Auftragsabwicklung, Produktion und Rechnungswesen.

+
+
+
PfadKritischster Pfad
+

Auftragsabwicklung → ERP (SAP) → Active Directory → Cloud-Backup

+
+
+
💡 Empfehlung
+

Redundanz für AD, priorisierte Wiederanlaufplanung, Risiko R-008 hochstufen.

+
+
+
+ + + + diff --git a/docs/ISMS-GUI-Verbesserungen-GEFIM.html b/docs/ISMS-GUI-Verbesserungen-GEFIM.html new file mode 100644 index 0000000..dd8a128 --- /dev/null +++ b/docs/ISMS-GUI-Verbesserungen-GEFIM.html @@ -0,0 +1,382 @@ + + + + + +GEFIM ISMS – GUI-Verbesserungen + + + + + + +
+
GEFIMGUI-Verbesserungen · Vorschlag
+
+

Vorschläge für Detailansicht & Bearbeiten

+

Zwei überarbeitete Screens auf Basis eurer aktuellen Umsetzung: klarere Hierarchie, visuelle Risikodarstellung, Bearbeiten als Slide-over mit einem sticky Speichern. Öffne die Screens und probiere sie aus.

+
+ +
+
+
+

Risiko-Detail · R-001 (neu)

+

Visueller Brutto→Rest-Verlauf, Maßnahmen als Karten mit Fortschritt, einheitliche C/I/A-Gauges.

+
Ansicht öffnen →
+
+
+
+

Prozess bearbeiten (neu)

+

Slide-over mit Sprungnavigation, Typeahead-Asset-Zuordnung, farbige Schadenshöhe, ein Speichern, Löschen im ⋯-Menü.

+
Formular öffnen →
+
+
+ +
+

Was konkret verbessert wurde

+
+
1
Ein sticky Speichern statt zwei getrennter Buttons — inkl. Autosave-Indikator.
+
2
Risikowert visualisiert: Brutto→Rest mit Pfeil und Position auf einer Farbskala.
+
3
Slide-over statt hohem Modal — Kontext bleibt erhalten, Sprungnavigation oben.
+
4
Einheitliches C/I/A-Gauge mit fester Farblogik (1→4) statt loser Zahlen.
+
5
Maßnahmen als Karten mit Status, Fortschritt und Minderungseffekt.
+
6
Löschen entschärft — im ⋯-Überlaufmenü statt neben Speichern.
+
7
Typeahead-Suche für Asset-Zuordnung mit Chips statt zwei Dropdowns.
+
8
Einheiten & Inline-Hilfe an Feldern, Fokus-Zustände, Live-Validierung.
+
+
Tipp für Power-User: Command-Palette mit ⌘ K für schnelle Navigation und Aktionen.
+
+
+ + +
+
+
+
+ + + + diff --git a/docs/ISMS-Lieferantenmanagement-GEFIM.html b/docs/ISMS-Lieferantenmanagement-GEFIM.html new file mode 100644 index 0000000..439e0f3 --- /dev/null +++ b/docs/ISMS-Lieferantenmanagement-GEFIM.html @@ -0,0 +1,393 @@ + + + + + +GEFIM ISMS – Lieferantenmanagement + + + + + + +
+
+
GEFIM
Lieferantenmanagement
VDA-ISA 2027 · Kapitel 6 „Supplier Relationships" · NIS2-Lieferkette
+
+
+
+
+ + + + diff --git a/docs/ISMS-Prototyp-GEFIM.html b/docs/ISMS-Prototyp-GEFIM.html new file mode 100644 index 0000000..ece0bea --- /dev/null +++ b/docs/ISMS-Prototyp-GEFIM.html @@ -0,0 +1,753 @@ + + + + + +GEFIM ISMS – Prototyp + + + + + + +
+ + + + +
+
+
+ + Muster Mittelstand GmbH + +
+ +
+ +
MS
+
+ +
+
+
+ + + + diff --git a/docs/KONZEPT-backup-restore.md b/docs/KONZEPT-backup-restore.md new file mode 100644 index 0000000..1079d6f --- /dev/null +++ b/docs/KONZEPT-backup-restore.md @@ -0,0 +1,135 @@ +# Konzept — Datensicherung, Wiederherstellung, DSGVO-Export & Löschung (certvia) + +> Status: **Konzept/Entscheidungsvorlage** (kein Code). Produkt: **certvia** (ISMS-Tool, Single-DB + Postgres-RLS, alle Mandanten in denselben Tabellen mit `tenant_id`). Kernidee: **eine mandanten-scoped Traversierungs-Engine** bedient vier Zwecke — Per-Tenant-Backup, gezielten Restore, DSGVO-Auskunft/-Export und DSGVO-Löschung/Offboarding. + +## 0. Zielbild +1. **Disaster-Recovery** der gesamten DB (Totalausfall, Ransomware, „Zeitpunkt-T-Wiederherstellung"). +2. **Gezielter Einzelkunden-Restore** (Kunde A zurück, Kunde B unangetastet) — über das **Betreiber-Portal**. +3. **DSGVO-Auskunft/-Datenportabilität** (Art. 15/20) — je Mandant und je betroffener Person. +4. **DSGVO-Löschung** (Art. 17) — ganzer Mandant (Offboarding) und einzelne Person, mit ISMS-konformer Aufbewahrung. + +Alle vier teilen sich **einen** Baustein: das Durchlaufen aller mandantengescopten Tabellen in FK-Reihenfolge, gefiltert auf `tenant_id` (bzw. auf eine Person). + +## 1. Architektur-Grundlage (bestehend, wird genutzt) +- **`TENANT_MODELS`** (`src/server/db.ts`) = autoritative Menge aller mandantengescopten Tabellen. Plus deren FK-Topologie ⇒ die verbindliche Reihenfolge für Export (parent→child) und Löschung (child→parent). +- **`tenant_id`-Spalte + RLS** ⇒ jede Operation `WHERE tenant_id = A` ist **beweisbar** auf einen Mandanten begrenzt. +- **cuid-Primärschlüssel** (kein Serial) ⇒ Reinsert kollisionsfrei, IDs bleiben erhalten, keine Sequenz-Konflikte. +- **Owner-`prisma`-Client** (BYPASSRLS) für Backup/Restore/Löschung; **nie** der RLS-Client. +- **Globale Tabellen** (Kataloge, `Permission`, `Tenant`-Stammsatz, künftig **`Identity`**) sind **nicht** tenant-scoped → über Schicht A gesichert, nicht Teil des Tenant-Artefakts. +- **MinIO/S3** hält Dateien/Logos je Mandant (Prefix) — DB-Backup allein reicht nicht. + +## 2. Schicht A — Cluster-Disaster-Recovery (ganze DB) +- **pgBackRest** oder **wal-g**: periodisches Vollbackup + kontinuierliches **WAL-Archiving** nach S3/offsite ⇒ **PITR** (Point-in-Time-Recovery). +- Zweck: Totalausfall/Ransomware/menschlicher Massenfehler → „DB auf Zeitpunkt T". +- **Verschlüsselt** (SSE-KMS oder client-seitig) — dockt an die (vorerst geparkte) DB-Härtung an. +- Deckt auch die **globalen** Tabellen inkl. `Identity`/Credentials ab, die Schicht B bewusst nicht anfasst. + +## 3. Schicht B — Mandanten-scoped Logical Export/Restore +### Export (Backup-Artefakt je Mandant) +- Aus **einem konsistenten Snapshot** (`REPEATABLE READ`-Transaktion), damit die FK-Integrität innerhalb des Mandanten stimmt. +- Je Tabelle aus `TENANT_MODELS`: `COPY (SELECT * FROM t WHERE tenant_id = 'A') TO …` → ein Artefakt (z. B. NDJSON/COPY) pro Mandant → gzip → verschlüsselt nach S3. +- Enthält **zusätzlich** den MinIO-Prefix des Mandanten (Datei-Snapshot) und ein **Manifest** (Schema-/Migrationsversion, Zeitstempel, Zeilenzahlen je Tabelle, Prüfsummen). +- Zeitplan: nächtlich + **on-demand vor riskanten Operationen** (Restore, Massen-Import). + +### Restore (gezielt Kunde A) +- Owner-Client, **eine Transaktion**, FK-Reihenfolge, alles `WHERE tenant_id = 'A'`: + 1. Mandant **sperren** (`status = SUSPENDED`) → keine parallelen Schreibzugriffe. + 2. **Pre-Restore-Sicherheitsschnappschuss** des aktuellen Standes (Restore ist damit reversibel). + 3. **Replace**: `DELETE … WHERE tenant_id='A'` (child→parent) + Reinsert aus dem Artefakt (parent→child). Constraints ggf. `DEFERRED`. + 4. MinIO-Prefix des Mandanten wiederherstellen. + 5. Mandant reaktivieren, **Audit** schreiben. +- **Beweisbar sicher** für andere Mandanten: keine Operation verlässt `tenant_id='A'`. +- Schema-Version im Manifest gegen aktuelle Migration prüfen; bei Differenz Artefakt vor Reinsert migrieren/abweisen. + +## 4. Betreiber-Portal — Restore-Flow +Restore ist eine **Betreiber**-Fähigkeit (kein Mandanten-Admin) → Plattform-Portal (`/admin`, `platformAuth`). +- **Auslöser:** Aktion „Wiederherstellen" auf `/admin/[id]`, gegated durch **`requirePlatformFullAdmin` + frischer MFA-Step-up** (`assertPlatformStepUp`). +- **Auswahl:** Mandant + Sicherungspunkt (Liste der Per-Tenant-Snapshots / PITR-Zeitpunkt) + **Vorschau/Dry-run** (Zeilenzahlen, Snapshot-Zeit) + **getippte Bestätigung** („RESTORE kunde-a"). +- **Ausführung als Hintergrund-Job im Worker** (BullMQ, vorhanden) — **nicht** inline in der Server-Action (Timeouts/Progress/Audit). Die Action **enqueued** nur. +- **Kontrollen:** Sperre während Restore · Pre-Restore-Schnappschuss · `tenant_id`-Scope · Plattform-Audit (wer/Mandant/Snapshot/wann) · MinIO mit. + +## 5. DSGVO-Export (Art. 15 Auskunft / Art. 20 Portabilität) +**Rollen (wichtig):** certvia ist **Auftragsverarbeiter**, der Mandant ist **Verantwortlicher**. Anfragen richten sich an den Mandanten; certvia liefert das **Werkzeug**. Deshalb existiert der Export an **zwei** Stellen: +- **Mandanten-Self-Service** (Mandanten-Admin, für die eigenen Betroffenen), +- **Betreiber-Portal** (AVV-Unterstützung / Ausfallhilfe). + +**Zwei Granularitäten:** +1. **Per-Mandant** — der gesamte Kundendatensatz (= das Backup-Artefakt aus §3, maschinenlesbar/JSON). Nutzen: Portabilität beim Anbieterwechsel, Offboarding-Kopie. +2. **Per-Betroffener** (eine natürliche Person) — alle personenbezogenen Zeilen dieser Person: `User` (Mitgliedschaft), Auth-Daten aus **`Identity`** (Existenz/E-Mail/MFA-Status — **keine** Secrets), sowie alle Referenzen (`owner_id`, `assigneeId`, `createdBy`, `AuditLog.actorId`, `TaskParticipant`, `Audit.*UserId`, …) und Freitext mit Personenbezug. + +**Format/Zustellung:** ZIP (JSON + zugehörige Dateien aus MinIO), erzeugt vom **Worker-Job**, Zustellung über **zeitlich begrenzten signierten Link** (nicht per Mail). Export wird **auditiert**. + +## 6. DSGVO-Löschung (Art. 17 „Recht auf Vergessenwerden") +**Zwei Scopes:** +1. **Mandanten-Löschung / Offboarding** — alle `tenant_id='A'`-Zeilen (child→parent, eine Transaktion) + MinIO-Prefix. Danach **globale Aufräumung**: eine `Identity` **ohne verbleibende Mitgliedschaft** wird gelöscht/anonymisiert. +2. **Einzelne Person (Betroffener)** — Kernspannung im ISMS: **Löschung vs. Nachweis-/Aufbewahrungspflicht**. + +**Löschen vs. Anonymisieren (die zentrale Design-Regel):** +- Datensätze, die aus **ISMS-/Nachweisgründen** oder wegen **rechtlicher Pflicht** (Art. 17 Abs. 3) erhalten bleiben müssen (v. a. **Audit-Trail**, Freigaben, Nachweise), werden **anonymisiert/pseudonymisiert** (Name/E-Mail → Tombstone, referenzielle Struktur bleibt), **nicht** hart gelöscht — sonst bricht die Nachvollziehbarkeit. +- Wo keine Aufbewahrungspflicht greift: **Hard-Delete**. +- Ergebnis: **Löschnachweis/„Deletion Certificate"** (wer/wann/Scope/was gelöscht vs. anonymisiert), auditiert. + +**Personen über mehrere Mandanten (Auth-Umbau!):** Jeder Mandant ist ein **eigener Verantwortlicher**. Löschung erfolgt **pro Mandant-Scope** (Mitgliedschaft + PII in dessen Datensätzen) — **nicht** global über alle Mandanten. Erst wenn **keine** Mitgliedschaft der Person mehr existiert, wird die **globale `Identity`** entfernt/anonymisiert. + +**Backups vs. Löschung (bekannte Spannung):** Unveränderliche Backups lassen sich nicht punktuell „aufbohren". Standard: Löschung wirkt auf **Live-Daten** + wird über eine **Tombstone-/Löschliste beim Restore erneut angewandt** (ein alter Snapshot bringt gelöschte PII nicht zurück); Backups laufen über **Retention** aus. Diese Regel muss dokumentiert und im Restore-Job erzwungen werden. + +## 7. Gemeinsame Engine (der Architektur-Gewinn) +Backup-Export, DSGVO-Export, Offboarding und Löschung teilen **eine** tenant-scoped Traversierung über `TENANT_MODELS` + FK-Topologie: +- Export = SELECT je Tabelle, `tenant_id`- oder personen-gefiltert. +- Restore = DELETE+INSERT, `tenant_id`-gescopt. +- Löschung = DELETE (child→parent) bzw. UPDATE-Anonymisierung, `tenant_id`- oder personen-gescopt. +Ein Baustein, vier Anwendungsfälle → geringe Redundanz, konsistentes Verhalten, ein Testfokus (Isolation). + +## 8. Schnittstelle zum Auth-Umbau (Identity) +- **Export einer Person** vereint globale `Identity` (Existenz/E-Mail/MFA-Status, **keine** Secrets) + alle Mitgliedschaften + zugewiesene/erstellte Objekte. +- **Restore eines Mandanten** holt **Mitgliedschaften** (`User`) zurück, **nicht** den globalen Credential-Store (der liegt in Schicht A). Fehlt beim Reinsert die referenzierte `Identity` → sauber behandeln (neu verknüpfen/Einladung). +- **Löschung** ist controller-scoped (pro Mandant); globale `Identity` erst bei 0 Mitgliedschaften. +⇒ Diese Punkte **jetzt** mitdesignen, **umsetzen nach** WS0 (Identity-Fundament). + +## 9. Verschlüsselung & Schlüssel (Entscheidung) +**Entscheidung:** **Client-seitige AES-256-Verschlüsselung mit einem Schlüssel pro Umgebung** — **nicht** allein auf Storage-SSE verlassen. Grund: das Artefakt ist verschlüsselt, **bevor** es S3/MinIO erreicht → der Speicher-Betreiber sieht nie Klartext (at-rest **und** in-transit **und** zero-knowledge vom Speicher). Beide Backup-Tools können das nativ (keine Zusatzkomponente). Dies ist das **gemeinsame Primitiv**, auf dem die Backup-Lane und die Härtungs-Lane bauen. + +**Stack (durchgängig AES-256, konsistent zur bestehenden TOTP-Verschlüsselung AES-256-GCM):** +| Schutzobjekt | Mechanismus | +|---|---| +| Host at-rest (`pgdata`, MinIO) | **LUKS / provider-verschlüsseltes Volume** (deckt physischen Plattendiebstahl/Decommission; transparent im Betrieb) | +| Cluster-Backup (Schicht A) | **pgBackRest** mit nativer **AES-256-Repo-Verschlüsselung** (`repo-cipher-type=aes-256-cbc` + `repo-cipher-pass`) → S3/MinIO | +| Per-Tenant-Export + DSGVO-Pakete (Schicht B) | **`age`** je Artefakt (X25519, encrypt-then-upload) | +| MinIO-Dateien | **restic** (eingebaute Verschlüsselung) oder MinIO-SSE als Defense-in-Depth | + +**Warum nicht SSE-only:** SSE (AWS SSE-KMS / MinIO KES+KMS) ist transparent, aber der Speicher-Betreiber hält die Schlüssel, und self-hosted MinIO-SSE bräuchte KES+KMS als Extra-Komponente. SSE gern **zusätzlich**, nicht als alleinige Zusicherung. + +**Schlüsselverwaltung:** +- **Jetzt (self-hosted VPS):** **ein** AES-256-Schlüssel (pgBackRest) + **ein** `age`-Keypair **pro Umgebung** (test/dev/prod getrennt), als **Coolify-Env-Secret** + **Offline-Kopie im Org-Passwortmanager** (versiegelt). +- **Register „restore-kritische Secrets":** führt zusammen — **Backup-Keys**, **Pepper**, **`MFA_ENC_KEY`**, `AUTH_SECRET`. Regeln: **niemals** im selben Bucket wie die verschlüsselten Artefakte; **Verlust des Keys = Verlust der Wiederherstellbarkeit**. +- ⚠ **Umgebungs-Secret-Kohärenz beim Restore:** Pepper und `MFA_ENC_KEY` stehen **nicht** im per-Mandant-Artefakt. Ein Restore in eine Umgebung mit **anderem** Pepper/`MFA_ENC_KEY` bricht **alle** Passwort-/MFA-Prüfungen. Restore daher nur in eine Umgebung mit **passenden** Secrets (oder Passwort-/MFA-Reset einplanen). +- **Später (Phase 2):** Upgrade-Pfad auf **HashiCorp Vault** oder Provider-KMS (Rotation/Audit/Trennung) — bewusst offen, nicht jetzt bauen. + +**Aufgabenteilung der Lanes:** die **Backup-Lane** ruft die Verschlüsselung auf (pgBackRest-Repo-Key bzw. `age`-Recipient); die **Härtungs-Lane** stellt Host-Encryption (LUKS) bereit und verwaltet/rotiert die Keys + das Secrets-Register. + +**Aufbewahrung & Test:** +- **Retention** je Schicht dokumentieren (DR-WAL/Base, Per-Tenant-Snapshots, DSGVO-Exporte) — dem DSB vorzulegen. +- **Restore-Test** regelmäßig + dokumentiert (der Prod-Runbook fordert das bereits für `pgdata`). + +## 10. Governance-/Sicherheitskontrollen (Zusammenfassung) +| Operation | Wer | Zusatzschutz | +|---|---|---| +| Cluster-PITR | Betreiber/Ops | Offsite-Zugriff, 4-Augen empfohlen | +| Tenant-Restore | Plattform-Full-Admin | **MFA-Step-up**, getippte Bestätigung, Mandant-Sperre, Pre-Restore-Snapshot, Audit | +| DSGVO-Export | Mandanten-Admin **oder** Betreiber | signierter Link, Audit | +| Löschung Person | Mandanten-Admin (Verantwortlicher) | Anonymisierungs-Regeln, Löschnachweis, Audit | +| Mandanten-Löschung | Plattform-Full-Admin | **MFA-Step-up**, getippte Bestätigung, Löschnachweis, MinIO + globale Identity-Aufräumung | + +## 11. Phasen & offene Entscheidungen +**Phasen:** +1. Schicht A (pgBackRest/wal-g + PITR + verschlüsselt) — unabhängig, **sofort** möglich. +2. Traversierungs-Engine über `TENANT_MODELS` (Export/Restore-Kern) — **nach WS0**. +3. Betreiber-Portal-Restore (Worker-Job + Kontrollen). +4. DSGVO-Export (per-Mandant + per-Person). +5. DSGVO-Löschung (Anonymisierung vs. Hard-Delete + Löschnachweis + Tombstone-on-Restore). + +**Offene Entscheidungen (für PM/DSB):** +- Retention-Fristen je Schicht (DSB-Vorgabe). +- Welche Tabellen/Felder bei Personen-Löschung **anonymisiert** (Nachweispflicht) vs. **hart gelöscht** werden — eine explizite **Feld-Klassifikation** ist nötig. +- Aufbewahrung/Weg der DSGVO-Export-Pakete (Ablauf des signierten Links). +- Ob per-Mandant-Snapshots als DSGVO-Portabilitätsformat genügen oder ein zusätzliches „menschenlesbares" Format nötig ist. diff --git a/docs/KONZEPT-backup-target.md b/docs/KONZEPT-backup-target.md new file mode 100644 index 0000000..72b2200 --- /dev/null +++ b/docs/KONZEPT-backup-target.md @@ -0,0 +1,57 @@ +# Konzept — Konfigurierbarer Backup-Zielspeicher (Backend + Lokal) (certvia) + +> Status: **Konzept/Entscheidungsvorlage** (kein Code). Produkt: **certvia**. Folge-Feature der Backup-Lane. Ziel: den Zielspeicher für Backup-/DSGVO-Artefakte **im Betreiber-Portal konfigurierbar** machen und **lokale (persistente) Speicherung** als vollwertige Option anbieten — nicht nur über Env. + +## 1. Ist-Zustand (`src/server/storage/backup-store.ts`) +- Es gibt bereits eine **`BackupStore`-Abstraktion** (`put/get/list/remove`) mit zwei echten Implementierungen: **`S3BackupStore`** (MinIO/S3) und **`LocalBackupStore`** (echte Byte-Persistenz). +- **Aber:** Die Wahl trifft `createBackupStore()` **einmalig beim Prozessstart, rein Env-basiert**: alle `S3_*` gesetzt → S3, sonst lokaler Ordner (`BACKUP_LOCAL_DIR` bzw. `/.backups`). Exportiert als **statisches Singleton** `backupStore`. +- **Nur 3 Nutzer:** `src/server/backup/export.ts`, `restore.ts`, `ops.ts`. +- **Schwächen:** (a) nicht im Backend wählbar; (b) der lokale Ordner liegt im Container → beim Redeploy **flüchtig**; (c) S3-Config nur als Env, nicht pro Betreiber pflegbar. + +## 2. Zielbild +- **Betreiber wählt im Portal** das Ziel: **Lokal** oder **S3/MinIO**, inkl. Config, mit „Verbindung testen". +- **Lokal ist persistent** (gemountetes Volume), nicht flüchtig. +- Env bleibt als **Fallback** funktionsfähig (Rückwärtskompatibilität). + +## 3. Datenmodell (`PlatformSetting`, Singleton erweitern) +Aktuell nur `mfaRequired`. Ergänzen: +- `backupTarget String @default("local")` — `local` | `s3` +- `backupLocalDir String?` — Pfad des lokalen Ziels (muss auf ein **gemountetes** Volume zeigen) +- `backupS3Endpoint / backupS3Bucket / backupS3Region / backupS3AccessKey String?` +- `backupS3SecretKeyEnc String?` — S3-Secret **verschlüsselt at-rest** über `src/server/secret-crypto.ts` (`encryptSecret`/`decryptSecret`, Schlüssel `MFA_ENC_KEY`/`AUTH_SECRET`) — **nie** Klartext in der DB. + +Migration additiv (nullable, Default `local`). Kein Backfill nötig. + +## 4. Store-Factory umbauen +- `backupStore`-Singleton → **`getBackupStore(): Promise`**: liest `PlatformSetting`, baut den passenden Store, entschlüsselt den S3-Key. +- **Präzedenz:** DB-Config (wenn `backupTarget` gesetzt/vollständig) → **sonst** Env (`S3_*` / `BACKUP_LOCAL_DIR`) → **sonst** lokaler Default `.backups`. So bleibt bestehendes Env-Deployment lauffähig. +- **Caching + Invalidierung:** Store memoisieren, bei Änderung der Backup-Settings invalidieren (Version/Timestamp aus `PlatformSetting.updatedAt`). +- Die **3 Call-Sites** (`export.ts`, `restore.ts`, `ops.ts`) von `backupStore` auf `await getBackupStore()` umstellen. +- **Fail-secure:** unvollständige S3-Config → klarer Fehler (nicht still auf lokal fallen, wenn `backupTarget=s3` gewählt wurde). + +## 5. Betreiber-UI +- Neue Seite im Plattform-Portal, z. B. **`/admin/backup`** (oder Abschnitt in den Plattform-Einstellungen). +- Gated: **`requirePlatformFullAdmin` + MFA-Step-up** (`assertPlatformStepUp`) — Betreiber-Config mit Credentials. +- Felder: Ziel-Radio (Lokal/S3), je nach Wahl die Config; **„Verbindung testen"** (Probe-`put`+`get`+`remove` eines winzigen Test-Keys) mit klarer Rückmeldung; Speichern über eine Action analog `setPlatformMfaRequired` (`platformSetting.upsert`, S3-Secret vor dem Schreiben verschlüsseln). + +## 6. Persistenz für „Lokal" (Compose) +- In `docker-compose.coolify.yml` ein **persistentes Volume** ergänzen (analog `pgdata`/`miniodata`): `backups:` und in **app + worker** unter dem Pfad aus `backupLocalDir` mounten (z. B. `/app/.backups`). Ohne Mount bleibt Lokal flüchtig. +- Doku-Hinweis: `backupLocalDir` muss innerhalb des gemounteten Pfads liegen. + +## 7. Sicherheit +- S3-Secret **nur verschlüsselt** in der DB (`secret-crypto`). +- Config-Bearbeitung nur **Full-Admin + Step-up**, auditiert. +- **`BACKUP_ENC_KEY`** (Artefakt-Verschlüsselung, `src/server/backup/crypto.ts`) bleibt **getrennt** vom Zielspeicher — Verschlüsselung des Inhalts ≠ Wahl des Speicherorts. +- Umgebungs-Secret-Kohärenz (Restore) unverändert: `BACKUP_ENC_KEY`/`PASSWORD_PEPPER`/`MFA_ENC_KEY` sind Env, nicht Artefakt (siehe `KONZEPT-backup-restore.md` §9). + +## 8. Tests +- `scripts/test-backup-*` erweitern: Store-Auflösung aus DB-Config (local & s3), Präzedenz DB→Env→Default, „Verbindung testen"-Pfad, Fail-secure bei unvollständiger S3-Config. +- Export→Restore end-to-end gegen **beide** Backends. + +## 9. Sofort testbar (ohne Umbau) +Schon heute: ohne `S3_*` fällt der Store auf **lokal** zurück → Export/Restore/DSGVO laufen (Artefakte im Container-`.backups`, **flüchtig**). Für einen schnellen Funktionstest genügt: **backup-worker + Redis** (vorhanden) + `BACKUP_ENC_KEY` (Fallback `AUTH_SECRET`). Der Umbau macht das Ziel **wählbar** und **persistent**. + +## 10. Offene Entscheidungen +- Eigene Seite `/admin/backup` vs. Abschnitt in bestehenden Plattform-Einstellungen. +- Mehrere Ziele/Profile (Primär + Offsite) — jetzt 1 Ziel, Mehrfachziele als Phase 2. +- Ob der lokale Pfad frei wählbar ist oder auf den gemounteten Volume-Pfad festgelegt wird (empfohlen: fest, um Fehlkonfiguration zu vermeiden). diff --git a/docs/KONZEPT-framework-iso27001.md b/docs/KONZEPT-framework-iso27001.md new file mode 100644 index 0000000..637b3fc --- /dev/null +++ b/docs/KONZEPT-framework-iso27001.md @@ -0,0 +1,162 @@ +# KONZEPT: Mehr-Framework-Fähigkeit — ISO 27001 neben TISAX (pro Mandant wählbar) + +**Stand:** 2026-08-21 · **Zielgruppe:** mehrköpfiges Entwicklerteam + PM · **Status:** Entwurf zur Abnahme + +> **Nachtrag 2026-08-21 — D4 und Lane 2 sind entschieden und umgesetzt:** Nicht zwei Seed-Pakete, +> sondern **ein Dokumentensatz mit zwei Framework-Mappings** (Variante A). Umsetzung und Begründung: +> `docs/FRAMEWORK-MAPPING-ISO27001.md`. Die übrigen Lanes bleiben unverändert gültig. + +> **Ziel:** Kunden sollen pro Mandant **ISO 27001 und/oder TISAX** wählen können. Je Framework gibt es u. a. ein eigenes Vorlagenpaket, einen eigenen Control-Katalog und eine eigene Audit-/Readiness-Logik. Heute ist das Tool durchgängig **implizit auf VDA-ISA 2027 / TISAX** verdrahtet. + +--- + +## 1. Ausgangslage (Ist-Analyse, belegt) + +Das Fachmodell kennt **kein** „Framework/Standard" pro Mandant. Alles ist implizit VDA-ISA/TISAX: +- **Kein Framework-Feld:** `Tenant` (`prisma/schema.prisma:31`) hat nur `sector` + generisches `config Json`; `TenantSettings` (`:52`) hat als einzigen Standard-Anker `tisaxLevel` (`:70`, „AL2|AL3"). ISO 27001 erscheint nur als Marketing-Text (`src/lib/brand.ts:57`) und in einem Kommentar (`src/server/actions/tenant-users.ts:197`). +- **Control-Katalog** liegt als **String-ID** vor (kein Enum): `ControlAssessment.control` (`:967`, z. B. „1.3.1"/„5.3.4-KI", Werte 0–3), `ControlImplementation.reqId` (`:988`), `ControlDescription` (`:1217`, „VDA-ISA-Spalte 4"). Titel/IDs kommen aus VDA-ISA (`src/lib/control-titles.ts:1`). `Domain`-Enum (`:1029`) enthält TISAX-only `PROTOTYPE`. +- **Ein** Vorlagenpaket verdrahtet: Parser `prisma/import-policies.ts` (Codes L00/R../VA-, `:115`), globale Ablage `PolicyTemplateVersion` (`:1637`, **ohne** Framework-Dimension), Auflösung `prisma/template-store.ts` (`resolvePackageForTenant` wählt nur nach Locale die *eine* neueste PUBLISHED-Version, `:147`), Sync-Skript `scripts/sync-policy-templates.ts:20` (fest `seed/isms-vorlagenpaket-v2` de/en, `meta.standard:"VDA ISA 2027"`, `version:"2.1"`). +- **Readiness/Reifegrad** ist TISAX: Reifegrad **0–3** (`src/lib/maturity.ts:11`), Zielgrad aus AL2/AL3 + Schutzbedarf (`src/server/assessment-level.ts`), Anforderungsschema MUSS/SOLL/HOCH/SEHR-HOCH + Prüfziele IS/Prototyp(8.)/Datenschutz(9.) (`src/lib/scope-filter.ts`, `src/lib/export/vda-isa.ts:9`). Die reinen Rechen-Engines `src/lib/readiness.ts` und `src/lib/gap-consolidation.ts` sind numerisch **standard-agnostisch**. +- **SoA** existiert als Modul-Key `soa` (`src/lib/modules.ts:19`), ist faktisch aber ein **VDA-ISA-Reifegrad-Assessment** (`src/server/actions/soa.ts`, Werte 0–3), **nicht** die ISO-typische Applicability-Erklärung (anwendbar/ausgeschlossen + Begründung je Annex-A-Control). +- **Provisionierung**: `provisionTenant` (`src/server/provision.ts:53`) ist die zentrale Stelle — schreibt `tisaxLevel`, aktiviert alle Module, importiert das *eine* Paket, setzt TISAX-Schutzbedarf-Flags. `ProvisionOpts` kennt kein `framework`. + +**Bereits standard-agnostisch (wiederverwendbar):** Multi-Tenancy/RLS, Modul-Toggle (`TenantModule`), Vorlagen-**Mechanik** (Parser-Struktur, nicht-destruktiver `reconcilePackage`, DB-Versionsablage, Locale-Fallback), Control-Speicherung als String-ID, Onboarding-Registry/Progress, die Rechen-Engines readiness/gap. + +**Hart an TISAX gekoppelt (abstrahieren/duplizieren):** AL2/AL3-Schutzbedarf + Flags, Reifegrad 0–3 + C5-Belegtabelle, MUSS/SOLL-Schema + Prüfziele 8./9., der eine Vorlagenpaket-Pfad + single-published-Auflösung, VDA-ISA-Exporte/Labels, Control-Titel, `Domain.PROTOTYPE`, die SoA-Semantik, zahlreiche i18n-Labels „TISAX"/„VDA-ISA". + +--- + +## 2. Zielbild + +Ein **Framework als First-Class-Dimension**: Mandant wählt ein oder mehrere Frameworks (`ISO_27001`, `TISAX`). Je Framework werden Vorlagenpaket, Control-Katalog, Scope-/Assessment-Modell, Readiness/SoA-Sicht und Export **framework-spezifisch** aufgelöst — über eine **Strategie-Schicht**, damit die generische Mechanik (Tenancy, Vorlagen-Import, Wizard-Shell, Rechen-Engines) unverändert bleibt. + +Leitprinzipien: +- **Additiv / Expand-Contract**: bestehende (Test-)Mandanten laufen unverändert als TISAX weiter; neue Spalten/Tabellen additiv, keine Datenmigration von Inhalten (nur Testdaten). +- **TISAX-Verhalten bleibt bit-genau erhalten** (Regressionsschutz) — ISO wird *daneben* gebaut, nicht *statt*. +- **Ein Mandant kann beide Frameworks führen** (n:m) — geteilte Belege/Policies, aber getrennte Katalog-/SoA-Sichten. +- **Feature-Flag**: ISO bleibt hinter einem Schalter, bis Katalog + Readiness + SoA abgenommen sind. + +--- + +## 3. Entscheidungen (D) — vom Team/PO zu bestätigen + +| # | Entscheidung | Empfehlung | Begründung | +|---|--------------|-----------|------------| +| **D1** | Framework-Kardinalität | **n:m** (Mandant kann ISO **und** TISAX) via eigener Tabelle `TenantFramework` | Nutzeranforderung „oder/und"; erlaubt per-Framework-Attribute (z. B. TISAX-Level, ISO-Zertifizierungsziel). | +| **D2** | `tisaxLevel` | bleibt vorerst auf `TenantSettings`, wird als **TISAX-scoped** dokumentiert (nur relevant, wenn TISAX aktiv); optional später in `TenantFramework.config` verschieben | Minimiert Migration + die ~356 dbForTenant-Aufrufstellen; kein Umbau bestehender Reads. | +| **D3** | Control-Speicherung | **String-ID beibehalten**, Framework als zusätzliche Dimension (kein Enum-Umbau) | `ControlAssessment.control` etc. nehmen ISO-Annex-A-IDs (A.5.1 …) ohne Schema-Bruch auf. | +| **D4** | Vorlagenpaket | ~~zweites Seed-Paket~~ → **entschieden 2026-08-21: ein Dokumentensatz, zwei Mappings** (`mapping.json` + `mapping-iso.json` in `seed/isms-vorlagenpaket-v2`). `framework`-Dimension auf `PolicyTemplateVersion` bleibt nötig (+ Unique `(framework, version)`). | Gleiche Dokument-Codes können in einem Mandanten nicht zweimal existieren (`@@unique([tenantId, code])`); der Umsetzungstext ist ohnehin normunabhängig. Siehe `FRAMEWORK-MAPPING-ISO27001.md`. | +| **D5** | Assessment-Modell | **Strategie-Interface** je Framework (Scope/Reifegrad/Ziel/SoA), TISAX = heutige 0–3/AL-Logik, ISO = SoA-Applicability + Umsetzungsstatus | ISO kennt kein AL2/AL3 und keine VDA-ISA-Reifegrade; saubere Trennung ohne TISAX-Regression. | +| **D6** | ISO-SoA | echte **Statement of Applicability** (Annex-A-Liste, anwendbar/ausgeschlossen + Begründung, Verknüpfung Policy/Evidence) — neu für ISO; TISAX behält sein Reifegrad-Assessment | ISO-27001-Kernartefakt fehlt heute fachlich. | +| **D7** | Rollout | **Feature-Flag** „ISO" + erst Test-Instanz; TISAX unverändert | Risikoarme Einführung; TISAX-Kunden unberührt. | +| **D8** | Katalog-Grundlage ISO | **Annex A (ISO/IEC 27001:2022, 93 Controls, 4 Themen)** + Klauseln 4–10 als Managementsystem-Anforderungen | Aktueller Normstand; 2022er Struktur. | + +--- + +## 4. Zielarchitektur + +### 4.1 Datenmodell (additiv) +- **`enum Framework { ISO_27001, TISAX }`**. +- **`model TenantFramework`** (n:m): `tenantId`, `framework`, `isPrimary Boolean`, `config Json` (per-Framework-Attribute, z. B. `{ tisaxLevel: "AL3" }` bzw. `{ certScope, certBodyTarget }`), Unique `(tenantId, framework)`. → in `TENANT_MODELS` (RLS) aufnehmen. +- **`PolicyTemplateVersion`**: neue Spalte `framework Framework`; Unique `(framework, version)` statt nur `version`; Default-Backfill `TISAX`. +- **`PolicyPackageState`** (Mandanten-Merker, `schema:1612`): um `framework` erweitern (je Framework eine importierte Version). +- **ISO-SoA** (neu): `model SoaEntry { tenantId, framework=ISO_27001, control (A.x.y), applicable Boolean, justification String, implementationStatus enum, linkedPolicyCode?, linkedEvidenceId? }` — RLS-scoped. +- **`Domain`-Enum**: ISO-Themen ergänzen bzw. `PROTOTYPE` als TISAX-only markieren; ISO-Controls mappen auf die 4 Annex-A-Themen (Organizational/People/Physical/Technological) → entweder neue Enum-Werte oder eine framework-abhängige Domain-Auflösung. + +### 4.2 Strategie-Schicht (Kernstück) +Ein `FrameworkStrategy`-Interface kapselt alle TISAX-spezifischen Annahmen; je Framework eine Implementierung: +``` +interface FrameworkStrategy { + key: Framework + resolvePackage(locale): PublishedPackage // template-store, framework-parametrisiert + loadCatalog(): { controls, titles, scope } // c1/c5/mapping bzw. Annex-A/Klauseln + scopeFilter(settings): ControlRow[] // TISAX: AL/Prüfziel · ISO: Applicability + targetFor(control, settings): AssessmentTarget // TISAX: Reifegrad 0–3 · ISO: Umsetzungsstatus/SoA + readinessView(rows): ReadinessSummary // nutzt generische readiness/gap-Engines + export(): ExportArtifact // TISAX: VDA-ISA · ISO: SoA + Annex-A-Gap + wizardSteps(): StepKey[] // framework-abhängige Sichtbarkeit/Inhalte +} +``` +Bestehende Dateien werden hinter diese Schnittstelle gezogen: `assessment-level.ts`, `maturity.ts`, `scope-filter.ts`, `control-titles.ts`, `export/vda-isa*.ts` → `TisaxStrategy`. Die generischen Engines `readiness.ts`/`gap-consolidation.ts` bleiben und werden von beiden Strategien gefüttert. + +### 4.3 Auflösung zur Laufzeit +- `template-store.ts`: `resolvePackageForTenant(tenant, framework, locale)` — wählt PUBLISHED-Version je `(framework, locale)`. +- `provisionTenant`: `ProvisionOpts.frameworks: Framework[]` → schreibt `TenantFramework`-Zeilen, importiert **je Framework** das passende Paket + Katalog, setzt nur bei TISAX die AL-Flags. +- UI/Server lösen die aktive Framework-Sicht über die Mandanten-`TenantFramework` + eine aktive Auswahl (bei Mehr-Framework: Umschalter, analog Mandantenwahl). + +--- + +## 5. Workstreams / Lanes für das Team + +Fünf Lanes + PM. Abhängigkeiten in Klammern. + +### Lane 1 — Framework-Kern (Datenmodell, Provision, Auflösung) *(Fundament, zuerst)* +- `Framework`-Enum, `TenantFramework`-Tabelle (+ RLS/`TENANT_MODELS`), `PolicyTemplateVersion.framework` (+ Unique), `PolicyPackageState.framework` — additive Expand-Migrationen + Backfill bestehender Daten auf `TISAX`. +- `ProvisionOpts.frameworks` + framework-abhängige Paket-/Katalog-Auflösung in `provision.ts`. +- `template-store.ts` framework-parametrisieren. +- **DoD:** bestehende Mandanten laufen unverändert (framework=TISAX), neuer Mandant kann mit `frameworks:[ISO_27001]` **oder** `[TISAX]` **oder** beiden provisioniert werden; Gate grün. + +### Lane 2 — ISO-Mapping & -Katalog *(inhaltlicher Teil erledigt; Rest braucht L1)* +- ✅ **erledigt (2026-08-21):** `mapping-iso.json` (27 Klauseln + 93 Annex-A-Controls) auf der bestehenden + Bibliothek; 19 ISO-only-Abschnitte ergänzt; Sichtbarkeit über `FLAG_FW_ISO27001`/`FLAG_FW_TISAX`; + SoA-Gerüst mit den Pflichtangaben aus 6.1.3 d); `_verify_iso.py` grün. +- ⬜ ISO-`control-titles`, ISO-Scope-/Control-Kataloge (Pendants zu `c1-scope.json`/`c5-controls.json`). +- ⬜ `parsePackageFiles`/`sync-policy-templates.ts` über **Frameworks × Sprachen** iterieren — heute ist + `mapping.json` fest verdrahtet, `mapping-iso.json` wird noch nicht gelesen. +- ✅ **erledigt:** Englische Fassung `isms-vorlagenpaket-v2-en` nachgezogen (eigene Texte, `--lang en`). +- **DoD:** ISO-Mapping importiert als eigene `PolicyTemplateVersion(framework=ISO_27001)`; ein ISO-Mandant + erhält Annex-A-Controls und sieht die ISO-Anforderungssicht. + +### Lane 3 — Assessment-/Readiness-Abstraktion *(braucht L1; parallel zu L2)* +- `FrameworkStrategy`-Interface; heutige TISAX-Logik als `TisaxStrategy` extrahieren (verhaltensgleich!). +- `IsoStrategy`: Scope = Applicability; Ziel = Umsetzungsstatus (statt Reifegrad 0–3); Readiness/Gap über die bestehenden generischen Engines. +- `readiness.ts`/`gap-consolidation.ts` framework-parametrisiert füttern; keine TISAX-Regression. +- **DoD:** TISAX-Readiness identisch zu heute (Snapshot-Test); ISO liefert eine erste Readiness-/Gap-Sicht auf Annex-A-Basis. + +### Lane 4 — ISO-SoA + Exporte *(braucht L2+L3)* +- Echte **SoA-Sicht** (`SoaEntry`): Annex-A-Liste, anwendbar/ausgeschlossen + Begründung, Verknüpfung Policy/Evidence, Umsetzungsstatus; Modul-Key `soa` beherbergt beide Sichten (TISAX-Reifegrad bleibt). +- ISO-Export: SoA-Dokument + Annex-A-Gap-Report; VDA-ISA-Export bleibt TISAX-only. +- **DoD:** ISO-Mandant kann eine vollständige SoA pflegen und exportieren. + +### Lane 5 — Wizard, Settings/Admin & i18n *(braucht L1; UI-Feinschliff am Ende)* +- Framework-Auswahl in Admin (Mandant anlegen) + `/settings`; `setTenantTisaxLevel` → TISAX-scoped, ISO-Zertifizierungsziel analog. +- Onboarding-Registry framework-aware (`getVisibleSteps` guard je Framework): TISAX behält Scope/AL/Prüfziel + Controls-Reifegrad; ISO ersetzt AL-Schritt durch Applicability/SoA-Schritt. +- i18n: framework-neutrale Labels + per-Framework-Overrides; „TISAX/VDA-ISA"-Strings entkoppeln (`messages/de.json`/`en.json`, `settings/page.tsx`, `audit-readiness/*`, `admin/page.tsx`). +- **DoD:** Kunde wählt im Admin ISO und/oder TISAX; der Wizard zeigt die passenden Schritte; keine „TISAX"-Labels bei reinen ISO-Mandanten. + +**PM:** Reihenfolge L1 → (L2 ∥ L3) → L4 → L5; Abnahme je Lane; Regressions-Gate für TISAX (Snapshot der heutigen Readiness/Exporte) als Pflicht vor jedem Merge. + +--- + +## 6. Migration & Rollout +- **Expand:** additive Migrationen (Enum, `TenantFramework`, Spalten); Backfill: für jeden bestehenden Mandanten `TenantFramework(framework=TISAX, isPrimary=true)`; `PolicyTemplateVersion.framework=TISAX`. +- **Feature-Flag** „ISO 27001" (Plattform-Setting) gated Admin-Auswahl + Provisionierung, bis L2–L4 abgenommen. +- **Keine Inhaltsmigration** (nur Testdaten); neue ISO-Mandanten frisch provisioniert. +- **Contract (später):** ungenutzte TISAX-only-Felder erst nach stabilem Mehr-Framework-Betrieb aufräumen (z. B. `tisaxLevel` → `TenantFramework.config`). + +## 7. Risiken & Gegenmaßnahmen +| Risiko | Gegenmaßnahme | +|--------|---------------| +| TISAX-Regression durch Refactoring | `TisaxStrategy` verhaltensgleich extrahieren; Snapshot-Tests der heutigen Readiness/Exporte als Merge-Gate. | +| ISO-Katalog-Qualität (Annex-A ↔ Policies) | Fachliches Mapping-Review (ISMS-Experte) vor L4; `mapping.json` als Single Source. | +| SoA-Semantik ist fachlich neu | Eigene Lane (L4) mit klarer Definition applicable/exclusion + Begründungspflicht. | +| Mehr-Framework-Komplexität in UI | Aktive-Framework-Umschalter analog Mandantenwahl; getrennte Katalog-Sichten. | +| `Domain.PROTOTYPE`/AL nur TISAX | Framework-abhängige Domain-/Scope-Auflösung; ISO ignoriert AL/Prototyp. | +| i18n-Wildwuchs „TISAX" | Zentrale framework-neutrale Keys + Overrides; Lint auf verbleibende Hardcodes. | + +## 8. Grobe Aufwandsschätzung +| Lane | Aufwand (PT, grob) | +|------|--------------------| +| L1 Framework-Kern | 4–6 | +| L2 ISO-Paket & Katalog (inkl. fachliches Mapping) | 8–12 | +| L3 Assessment-Abstraktion | 5–8 | +| L4 ISO-SoA + Exporte | 5–8 | +| L5 Wizard/Settings/i18n | 4–6 | +| PM/Fachreview | durchgehend | +| **Summe** | **~26–40 PT**, L2/L3 parallelisierbar | + +## 9. Offene Punkte (vom PO/Fachexperten zu klären) +- Umfang ISO-Vorlagenpaket: nur Annex-A-Controls oder auch Managementsystem-Klauseln 4–10 als geführte Artefakte? (Empfehlung: beides.) +- ~~Wie stark sollen ISO- und TISAX-Sicht bei Doppel-Framework **Belege/Policies teilen**?~~ → **entschieden:** ein gemeinsames Policy-Set, zwei Mappings (Variante A, 2026-08-21). +- ISO-Reifegrad optional zusätzlich zur Applicability (manche Kunden wollen Reifegrade auch unter ISO)? +- Zielformat ISO-Exporte (SoA-Dokument als Word/PDF/XLSX; Annex-A-Gap als XLSX). diff --git a/docs/KONZEPT-garage-migration.md b/docs/KONZEPT-garage-migration.md new file mode 100644 index 0000000..af4e53b --- /dev/null +++ b/docs/KONZEPT-garage-migration.md @@ -0,0 +1,217 @@ +# KONZEPT: Objektspeicher-Migration MinIO → Garage + +**Stand:** 2026-08-20 · **Zielgruppe:** mehrköpfiges Entwicklerteam + PM · **Status:** Entwurf zur Abnahme + +> **Randbedingung (2026-08-20):** Es existieren **nur Test-Instanzen** — **keine produktiven Daten**. Daher **keine Datenmigration** (kein rclone-Sync), sondern ein **kompletter Neu-Deploy** mit frischer Garage. Das eliminiert die frühere Migrations-Lane und das Wartungsfenster; Cutover = MinIO-Service durch Garage ersetzen, provisionieren, neu deployen (optional DB-Reset wie gehabt). + +--- + +## 1. Ausgangslage & Motivation + +certvia nutzt aktuell **MinIO** als S3-kompatiblen Objektspeicher (Dokument-Uploads + Backup-Artefakte). Anlass für die Prüfung: der Hinweis, MinIO werde „nicht mehr weiterentwickelt". + +**Faktenlage (verifiziert 2026-08-20):** + +- **Mai 2025** — MinIO entfernt die Admin-Konsole/Verwaltungs-GUI aus der Community Edition (nur noch rudimentärer Object-Browser; Bucket-/User-/Policy-Verwaltung nur noch im kommerziellen AIStor). +- **Okt 2025** — MinIO publiziert keine Container-Images mehr auf Docker Hub/Quay (auch nicht für einen kritischen CVE-Fix). +- **Dez 2025** — Community-Repo im **Maintenance-Mode**: keine neuen Features, keine PRs, Security-Fixes nur „case-by-case"; Repo als **„no longer maintained"** markiert. Fokus liegt auf **AIStor** (Abo-Produkt). Der Code bleibt AGPLv3 verfügbar. + +**Bewertung:** MinIO ist nicht „von heute auf morgen tot", aber die **Community Edition ist faktisch im End-of-Life-/Wartungsmodus**. Für ein selbstgehostetes ISMS-/Compliance-Produkt (das genau Betriebs-, Wartungs- und Supply-Chain-Sicherheit demonstrieren soll) ist der proaktive Wechsel auf einen aktiv gepflegten Store gerechtfertigt und gut begründbar (u. a. relevant für die eigene Lieferanten-/Komponentenbewertung). + +**Warum Garage:** aktiv entwickelt (Deuxfleurs, AGPLv3, Rust), bewusst **minimalistisch & leichtgewichtig**, S3-kompatibel, für Selbsthosting/kleine bis mittlere Deployments und geo-verteilte Replikation ausgelegt. Passt zum internen Coolify-Testserver **und** zum Contabo-Prod-VPS. + +--- + +## 2. Zielbild + +Ein **API-kompatibler Austausch** des Storage-Backends: Der Anwendungscode spricht weiterhin S3 (AWS SDK v3, `forcePathStyle`), lediglich der Container-Dienst, die Provisionierung von Bucket/Key und die Daten werden migriert. **Keine Änderung an Fachlogik, UI oder Datenmodell.** + +Was gleich bleibt: +- S3-Protokoll, AWS SDK v3, `forcePathStyle: true`, die Env-Kontrakte `S3_ENDPOINT / S3_ACCESS_KEY / S3_SECRET_KEY / S3_BUCKET / S3_REGION`. +- Die Storage-Abstraktionen `src/server/storage/adapter.ts` (Uploads) und `src/server/storage/backup-store.ts` (Backups) inkl. Local-/Stub-Fallback. +- Key-Schema (`/uploads/-`), Mandanten-Isolation über Key-Präfix. + +--- + +## 3. Ist-Analyse certvia (Code-Stand dev) + +Zwei S3-Konsumenten, beide identischer S3-Dialekt: + +| Konsument | Datei | Zweck | Ops | +|-----------|-------|-------|-----| +| Upload-Storage | `src/server/storage/adapter.ts` | hochgeladene Richtlinien + Audit-Nachweise | Put/Get, HeadBucket→CreateBucket | +| Backup-Store | `src/server/storage/backup-store.ts` | verschlüsselte Backup-Artefakte (`.cvb`), DSGVO-ZIP | Put/Get/List/Delete, HeadBucket→CreateBucket | + +Gemeinsam: +- `new S3Client({ endpoint, region, forcePathStyle: true, credentials })` — **path-style**, exakt was Garage erwartet. +- Verwendete S3-Operationen: `PutObject`, `GetObject`, `HeadBucket`, `CreateBucket`, `ListObjectsV2`, `DeleteObjects`. **Alle außer `CreateBucket` sind Garage-Standard.** +- Region-Default `us-east-1`. +- Backend-Auswahl rein über Env → sauberer Graceful-Fallback (Stub/Local), kein Hardcoding auf MinIO. + +**Zu provisionierende Buckets (Neu-Deploy, keine Altbestände zu übernehmen):** +- `S3_BUCKET` = `isms-documents` (Uploads). +- Backup-Bucket: nur falls der Backup-Store auf S3 statt lokal (`BACKUP_LOCAL_DIR`) betrieben wird — dann eigenen Bucket provisionieren. + +### Der einzige echte Reibungspunkt: Bucket-/Key-Anlage + +Garage verwaltet **Buckets und Access-Keys sowie deren Rechte** über die **Garage-Admin-API / `garage`-CLI**, **nicht** über die S3-Operation `CreateBucket`. Konsequenz: +- `HeadBucket`, `PutObject`, `GetObject`, `ListObjectsV2`, `DeleteObjects` → funktionieren gegen Garage unverändert. +- `CreateBucket` (unsere Selbstheilung „Bucket fehlt → anlegen") → **wird von Garage über die S3-API nicht bedient**. Buckets/Keys müssen **vorab out-of-band** provisioniert werden. + +> Hinweis: `backup-store.ts` **schluckt** einen `CreateBucket`-Fehler bereits (Bucket gilt als „vorhanden angenommen"), `adapter.ts` **wirft** dagegen bei nicht-„already exists"-Fehlern. Nach Vorab-Provisionierung greift ohnehin nur der `HeadBucket`-Erfolgspfad — trotzdem soll `ensureBucket()` explizit Garage-tauglich gemacht werden (siehe Lane C), damit wir uns nicht auf verschlucktes Fehlerverhalten verlassen. + +--- + +## 4. Entscheidungen (D) — vom Team/PO zu bestätigen + +| # | Entscheidung | Empfehlung | Begründung | +|---|--------------|-----------|------------| +| **D1** | Zielspeicher | **Garage, self-hosted — ENTSCHIEDEN 2026-08-20** | Aktiv gepflegt, S3-kompatibel, leichtgewichtig, DSGVO/Datenresidenz in eigener Hand. Alternativen (SeaweedFS, Ceph/RGW, extern R2/Hetzner) in §12 abgewogen. | +| **D2** | Region-Handhabung | Garage-`s3_region` = **`us-east-1`** setzen | App-Env bleibt unverändert (Default `us-east-1`) → keine Code-/Config-Drift. | +| **D3** | `ensureBucket()` | **Vorab-Provisionierung** + `ensureBucket` prüft nur (HeadBucket), kein S3-CreateBucket | Deterministisch; klare Fehlermeldung „Bucket nicht provisioniert" statt stiller Selbstheilung. | +| **D4** | Cutover-Strategie | **Neu-Deploy, kein Wartungsfenster** (MinIO→Garage im Compose ersetzen, provisionieren, deployen; optional DB-Reset) | **Keine produktiven Daten** → keine rclone-Migration nötig. | +| **D5** | Topologie | **Single-Node** Garage pro Environment | Passt zur aktuellen 1-Host-Topologie; Multi-Node/Replikation als spätere Ausbaustufe dokumentieren. | +| **D6** | Deployment | Garage als **Compose-Service** in `docker-compose.coolify.yml` (ersetzt `minio`) | Gleiches Betriebsmodell wie bisher (Coolify/Traefik). | +| **D7** | Reihenfolge | Aktuell nur **Test-Instanz(en)** — dort umsetzen; Prod später nach gleichem Muster | Es gibt derzeit keine Prod-Instanz; Runbook bleibt für spätere Prod gültig. | + +Strategische Vorfrage (self-hosted vs. externer managed S3): **entschieden am 2026-08-20 zugunsten self-hosted Garage** — Datenresidenz + Betriebshoheit für ein DSGVO-/ISMS-Produkt. Externe Optionen (Hetzner OS/Cloudflare R2) bleiben nur als dokumentierte Alternative in §12. + +--- + +## 5. Zielarchitektur + +``` + ┌───────────────────────── Coolify-Stack (pro Environment) ─────────────────────────┐ + app ──S3──► │ garage (Container) │ + worker ─S3► │ ├─ garage.toml (rpc_secret, s3_api.s3_region=us-east-1, api_bind_addr :3900, │ + backup- ─S3► │ │ admin_token, metadata_dir, data_dir) │ + worker │ ├─ Volume: garage_meta → /var/lib/garage/meta (KRITISCH: Metadaten/Layout) │ + │ └─ Volume: garage_data → /var/lib/garage/data (Objekt-Bytes) │ + │ garage-provision (Init-Job, restart:no): Layout + Bucket + Key + Rechte via CLI │ + └────────────────────────────────────────────────────────────────────────────────────┘ +``` + +- **Endpoint:** `S3_ENDPOINT=http://garage:3900` (S3-API-Port; Standard 3900). Admin-API auf 3903 (nur intern). +- **Zwei Ports beachten:** 3900 = S3, 3902 = Web (optional), 3903 = Admin. Nur S3 wird von der App genutzt; Admin bleibt clusterintern. +- **Secrets (pro Environment via Coolify-Env, echte Werte NIE im Chat/Repo):** `GARAGE_RPC_SECRET` (32-byte hex), `GARAGE_ADMIN_TOKEN`, plus der erzeugte Access-Key/Secret, die als `S3_ACCESS_KEY/S3_SECRET_KEY` in die App gehen. +- **Backup der Garage-Metadaten:** `garage_meta` enthält Bucket-/Key-/Layout-Definitionen — muss in die Host-Backup-Strategie (analog `pgdata`). Ohne Meta sind die Daten nicht adressierbar. + +--- + +## 6. Workstreams / Lanes für das Team + +Vier parallelisierbare Lanes + PM-Koordination (die frühere rclone-Migrations-Lane entfällt, da Neu-Deploy). Abhängigkeiten in Klammern. + +### Lane A — Infra & Deployment (Owner: DevOps) +- Garage-Service in `docker-compose.coolify.yml` ergänzen (Image pinnen, Ports, 2 Volumes, `security_opt`/`cap_drop` analog bestehender Services, Healthcheck auf Admin-API `/health`). +- `garage.toml` als Config (über Env/Coolify-Mount): `rpc_secret`, `s3_region=us-east-1`, `metadata_dir`, `data_dir`, `admin_token`. +- Single-Node-Layout initial (Node einer Zone mit Kapazität zuweisen — ohne Layout kein Schreibzugriff). +- `minio`-Service erst **nach** abgenommenem Garage-Betrieb entfernen (bis dahin als Rollback-Sicherheitsnetz stehen lassen). +- Garage-`meta`-Volume in Host-Backup aufnehmen. +- **Liefergegenstand:** lauffähiger Garage-Container auf der Test-Instanz, Admin-API erreichbar, Layout „ready". + +### Lane B — Provisioning-Automatisierung (Owner: DevOps/Backend) — *(braucht A)* +- Init-Job `garage-provision` (restart:no, analog `migrate`): idempotent + 1. Layout anwenden (falls noch nicht), + 2. Bucket(s) anlegen (`isms-documents`, ggf. Backup-Bucket), + 3. Access-Key erzeugen **oder** vorhandenen importieren, + 4. Key→Bucket-Rechte (read/write/owner) setzen. +- Umsetzung über `garage`-CLI **oder** Admin-API (HTTP) — Entscheidung dokumentieren; idempotent (mehrfach ausführbar ohne Fehler). +- Ausgabe des Access-Key/Secret **nur** in Coolify-Secrets, nicht in Logs. +- **Liefergegenstand:** ein Skript/Job, der aus „leerer Garage" reproduzierbar den betriebsbereiten Zustand herstellt (dokumentiert in `docs/DEPLOY-*`). + +### Lane C — App-Code-Anpassung (Owner: Backend) — *(unabhängig, klein)* +- `ensureBucket()` in **beiden** Stores Garage-tauglich: `HeadBucket` zur Verifikation; bei „missing" **kein** S3-`CreateBucket`, sondern klarer Konfigurationsfehler „Bucket nicht provisioniert — Provisioning-Job ausführen". (Provisionierung liegt bei Lane B.) +- Optional: gemeinsame S3-Client-Factory extrahieren (DRY über `adapter.ts`/`backup-store.ts`) — nur wenn ohne Risiko. +- Region/Endpoint-Doku in `.env.coolify.example` + `.env.example` aktualisieren (MinIO-Kommentare → Garage; `forcePathStyle`-Begründung bleibt gültig). +- **Tests:** bestehende `scripts/test-backup-*.ts` + Upload/Download-Pfad gegen einen lokalen Garage-Container grün; neuer Smoke-Test „Bucket fehlt → sprechender Fehler". +- **Liefergegenstand:** PR mit Code + aktualisierten Tests, `tsc/lint/build` grün. + +### Lane D — Test, Cutover & Abnahme (Owner: QA/DevOps + PM) — *(integriert A–C)* +- End-to-End-Durchstich auf der **Test-Instanz** (Neu-Deploy): Upload, Download, Backup-Export (`.cvb`), DSGVO-ZIP, Restore, Mandanten-Isolation. +- **Cutover-Runbook** (siehe §7) an der Test-Instanz **einmal durchspielen** (MinIO raus, Garage rein, provisionieren, deployen, ggf. DB-Reset). +- **Rollback-Runbook** (siehe §8). +- Abnahmekriterien (§9) abhaken. +- **Liefergegenstand:** abgenommene Test-Instanz auf Garage + freigegebenes Runbook (auch für spätere Prod). + +**PM:** Reihenfolge/Abhängigkeiten (A→B, C parallel, D integriert), Abnahme je Lane, Freigabe des Runbooks für spätere Prod (D7). + +--- + +## 7. Cutover-Runbook (Neu-Deploy, kein Wartungsfenster nötig) + +1. Im Compose `minio`-Service durch `garage` + `garage-provision` (Init-Job) ersetzen; Volumes `garage_meta`/`garage_data` anlegen. +2. Coolify-Env setzen: `S3_ENDPOINT=http://garage:3900`, `S3_REGION=us-east-1`, `GARAGE_RPC_SECRET`, `GARAGE_ADMIN_TOKEN` (literal, echte Werte NICHT aus dem Chat). `S3_ACCESS_KEY/S3_SECRET_KEY` = der beim Provisioning erzeugte Garage-Key. +3. Deploy: Garage startet, Layout „ready", `garage-provision` legt Bucket(s) + Key + Rechte an. +4. Optional **DB-Reset** (wie in bisherigen Deploys), falls alte Objekt-Referenzen im Datenbestand stören — bei frischer/geseedeter Test-Instanz meist unnötig. +5. **Smoke-Tests** (§9) aktiv durchführen. +6. `minio`-Service + Volumes entfernen; Garage-`meta`-Volume in Host-Backup bestätigen. + +## 8. Rollback + +- Da es **keine produktiven Daten** gibt, ist Rollback unkritisch: Compose zurück auf `minio` (oder frischer Re-Deploy). Optional den alten `minio`-Service während der ersten Testphase noch nicht löschen (Schritt 6 verzögern), bis Garage abgenommen ist. + +--- + +## 9. Validierung / Abnahmekriterien + +Gegen Garage müssen grün sein: +- **Upload:** Richtlinie hochladen → Objekt in Garage, `/uploads/...`-Präfix korrekt. +- **Download:** Datei abrufen (`/files/[...key]`), Content-Disposition/Filename-Metadatum stimmt. +- **Backup-Export:** `.cvb`-Artefakt erzeugt (CVB1-Header), Persistenz + Download. +- **DSGVO-ZIP:** erzeugt und lesbar. +- **Restore:** Backup → Wiederherstellung, Datenintegrität, **Mandanten-Isolation** gewahrt. +- **List/Delete:** Backup-Historie listet, Aufräumen entfernt Prefix. +- **Fehlerfall:** fehlender Bucket → sprechender Konfigfehler (kein stiller CreateBucket-Versuch). +- **Automatisiert:** `scripts/test-backup-*.ts` grün gegen Garage; `tsc/lint/build` grün. + +--- + +## 10. Risiken & Gegenmaßnahmen + +| Risiko | Gegenmaßnahme | +|--------|---------------| +| `CreateBucket` (S3) gegen Garage nicht verfügbar | Vorab-Provisionierung (Lane B) + `ensureBucket` nur prüfend (Lane C). | +| Garage-`meta`-Volume nicht gesichert → Buckets/Keys „weg" | Meta-Volume in Host-Backup; im Runbook explizit verifiziert. | +| Region-/Endpoint-Mismatch (Coolify-Env vs. `garage.toml`) | D2 fixiert `us-east-1` beidseitig; in Abnahme geprüft. | +| Access-Key/Secret landet in Logs | Provisioning schreibt nur in Coolify-Secrets; Log-Redaction. | +| Layout nicht angewendet → Schreibfehler „no capacity" | Provisioning-Job setzt Layout idempotent; Healthcheck. | +| Coolify-Interpolations-/„managed"-Fallen (bekannt) | Neue Env (`GARAGE_*`) literal setzen, nicht über `${…}` referenzieren; im Container-Env verifizieren. | +| Presigned URLs / spezielle S3-Features | certvia nutzt aktuell keine Presigned-URLs (Downloads laufen serverseitig) — vor Ausbau prüfen. | + +--- + +## 11. Grobe Aufwandsschätzung + +| Lane | Aufwand (Personentage, grob) | +|------|------------------------------| +| A Infra/Deployment | 2–3 | +| B Provisioning | 2–3 | +| C App-Code | 1–2 | +| D Test/Cutover/Abnahme | 1–2 | +| PM/Koordination | durchgehend | +| **Summe** | **~6–10 PT** (ohne Datenmigration), gut parallelisierbar | + +--- + +## 12. Alternativen (zur Vollständigkeit für D1) + +| Option | Pro | Contra | +|--------|-----|--------| +| **Garage** (empfohlen) | aktiv, leicht, S3, self-hosted, DSGVO in eigener Hand | Bucket/Key via Admin-API (einmaliger Provisioning-Aufwand); kein Erasure-Coding (Replikation) | +| SeaweedFS | performant, S3-Gateway, aktiv | größerer Funktionsumfang/komplexer als nötig | +| Ceph/RGW | Enterprise-Standard, sehr robust | schwergewichtig, hoher Betriebsaufwand — für 1-Host überdimensioniert | +| Externer managed S3 (Hetzner OS / Cloudflare R2) | kein Storage-Ops, hohe Verfügbarkeit | Datenresidenz/Abhängigkeit extern; Kosten; DSGVO-AV nötig | + +--- + +## 13. Quellen (MinIO-Status / Garage-Provisioning) + +- MinIO users complain after admin UI removed from Community Edition — blocksandfiles.com (2025-06) +- MinIO Faces Fallout for Stripping Functions from Open Source Version — futuriom.com (2025-06) +- MinIO Ends Community Development, Positions AIStor as the Future — faun.dev / devopslinks +- MinIO in Maintenance Mode: Open Source Alternatives — bizety.com (2025-12) +- minio/minio Discussion #21326 „It's not a feature issue, it's a trust one" — github.com +- Garage — Administration API / Features / Bucket & Key Operations — garagehq.deuxfleurs.fr, deepwiki.com + +*(Quellen-Status zeitkritisch; vor Projektstart kurz gegenprüfen.)* diff --git a/docs/KONZEPT-haertung.md b/docs/KONZEPT-haertung.md new file mode 100644 index 0000000..76c5b78 --- /dev/null +++ b/docs/KONZEPT-haertung.md @@ -0,0 +1,50 @@ +# Konzept — Sicherheitshärtung (Lane H) + +> Status: **Entscheidungsvorlage / Backlog** (kein Code). Produkt: **certvia** (ISMS-Tool). Freigegeben, weil der Auth-Umbau (Option C, WS0–WS5 + Contract) abgeschlossen ist. **Parallel** zur Backup-Lane baubar. Trifft die Backup-Lane genau am **gemeinsamen Verschlüsselungs-Primitiv** (§9 in `docs/KONZEPT-backup-restore.md`). + +## 0. Umfang +Alles unter „DB-/Plattform-Härtung", das **nicht** ins Backup-Konzept gehört: **Pepper**, **Host-Encryption at-rest**, **verschlüsselte Backups** (operativer Bezug zu §9), **DB-Connection-TLS**, **Secrets-Register**. Argon2-Parameter sind **erledigt**. + +## 1. Pepper (Passwort-Hash) — App-Härtung +**Ist:** `src/server/password.ts` nutzt Argon2id mit fixierten Parametern (`ARGON2_OPTIONS`), **Salt automatisch**, **kein Pepper**. +**Soll:** globaler **Pepper** über die Argon2-`secret`-Option — bei `hash()` **und** jeder `verify()`-Stelle. +- **Schlüsselquelle:** neues Umgebungs-Secret `PASSWORD_PEPPER` (32-Byte hex), analog `MFA_ENC_KEY`. +- **Umsetzung schlank dank Option C:** der verify-Pfad ist nach WS1/WS4 zentralisiert (Login gegen Identity) → `secret` an genau den zentralen hash/verify-Helfer geben statt an 6 verstreute Stellen. Bevorzugt einen `verifyPassword(hash, pw)`-Wrapper einführen (falls noch nicht), damit Pepper **eine** Stelle ist. +- ⚠ **Nicht rotierbar** ohne Passwort-Reset für alle (kein Rehash-on-Login) — wie `MFA_ENC_KEY`. Deshalb **jetzt setzen, solange test/dev-DBs frisch/leer sind**. +- **Restore-Kohärenz:** Pepper ist ein **Umgebungs-Secret**, steht nicht in Backup-Artefakten → Restore nur in Umgebung mit passendem Pepper (siehe Backup-Konzept §9). +**Dateien:** `src/server/password.ts` (+ zentraler verify-Wrapper), alle `verify()`-Aufrufer, `.env*`-Beispiele, Deploy-Env. + +## 2. Host-Encryption at-rest (Live-DB + Objektspeicher) +**Ist:** `pgvector/pgvector` (Community-Postgres, **kein TDE**); `pgdata`/MinIO-Volumes liegen im Klartext auf der VPS-Platte. +**Soll:** **LUKS/dm-crypt** bzw. **provider-verschlüsseltes Volume** für das Daten-Volume (deckt `pgdata` **und** MinIO). +- Schützt gegen physischen Plattendiebstahl/Decommission; transparent im Betrieb (im RAM entschlüsselt) — **kein** Schutz gegen Live-Server-Kompromittierung (dafür App-Feld-Encryption + Zugriffskontrollen). +- Operativer Runbook-Punkt (nicht App-Code): einmalig einrichten, in `docs/DEPLOY-PROD-CONTABO.md` als Go-Live-Checkliste ergänzen. + +## 3. Verschlüsselte Backups (operativer Bezug zu §9) +Setzt die Entscheidung aus `docs/KONZEPT-backup-restore.md` §9 **operativ** um: +- **pgBackRest** mit `repo-cipher-type=aes-256-cbc` + `repo-cipher-pass` → S3/MinIO. +- **`age`** für Per-Tenant-/DSGVO-Artefakte; **restic** für MinIO-Dateien. +- Verdrahtung in Coolify (Cron/Job + Zugangsdaten), Retention, **Restore-Test** dokumentieren. + +## 4. DB-Connection-TLS +**Ist:** `DATABASE_URL`/`RLS_DATABASE_URL` ohne `sslmode` → App↔Postgres **ohne** TLS, aber netz-isoliert (internes Docker-Netz `backend`, `internal: true`). +**Soll:** `sslmode=require` (bzw. `verify-full` mit CA) **sobald** die DB je den Host/eine Vertrauensgrenze verlässt (managed DB, eigener DB-Host). Aktuell durch die Netz-Isolation gemindert → **Phase 2 / bedingt**, nicht dringlich. + +## 5. Secrets-Register „restore-/betriebs-kritisch" +Ein gepflegtes Register (Ort: Org-Passwortmanager) mit Ownership + Rotationsregel: +| Secret | Zweck | Rotierbar? | +|---|---|---| +| `AUTH_SECRET` | Session-/JWT-Signatur | ja (invalidiert Sessions) | +| `MFA_ENC_KEY` | TOTP-Secret-Verschlüsselung (AES-256-GCM) | **nein** ohne MFA-Neueinrichtung | +| `PASSWORD_PEPPER` | Passwort-Pepper (neu, §1) | **nein** ohne Passwort-Reset | +| pgBackRest-Repo-Key | Cluster-Backup-Verschlüsselung | ja (mit Repo-Rekey) | +| `age`-Keypair | Per-Tenant-/DSGVO-Artefakte | ja (neue Artefakte) | +Regeln: **je Umgebung getrennt** (test/dev/prod); **niemals** im selben Bucket wie die Artefakte; Offline-Kopie versiegelt. + +## 6. Erledigt (nur Verweis) +- **Argon2id-Parameter** fixiert/dokumentiert (`src/server/password.ts`, `ARGON2_OPTIONS`) — gemerged. +- **TOTP-Secrets** AES-256-GCM at-rest (`src/server/secret-crypto.ts`, SEC3-d) — bestand bereits. + +## 7. Phasen & offene Entscheidungen +**Phasen:** (1) Pepper (App, jetzt — leere DBs). (2) Host-Encryption + verschlüsselte Backups (Ops, mit Backup-Lane). (3) Secrets-Register formalisieren. (4) DB-TLS + Vault/KMS = Phase 2. +**Offen (PM/ISB/DSB):** Pepper-Env-Name bestätigen + „nicht rotierbar" akzeptieren · Vault/KMS-Zeitpunkt · optional Spalten-Verschlüsselung (pgcrypto) für besonders sensible PII. diff --git a/docs/KONZEPT-identity-mandanten.md b/docs/KONZEPT-identity-mandanten.md new file mode 100644 index 0000000..c707e8e --- /dev/null +++ b/docs/KONZEPT-identity-mandanten.md @@ -0,0 +1,98 @@ +# Umsetzungskonzept — Zentrale Identität mit Mandanten-Mitgliedschaften (Option C) + +> Status: **Entscheidungsvorlage** (ohne Code). Ziel: eine Person meldet sich mit **einem** Login/Passwort und **einer** MFA an und wählt anschließend, in **welchem Mandanten** sie arbeitet — mit je Mandant unterschiedlichen Rollen. Die mandantengetrennte Datenhaltung (RLS, Ownership) bleibt **unangetastet**. + +## 1. Grundmodell in einem Satz +Eine **globale `Identity`** (E-Mail + ein Passwort + eine MFA) verweist auf **N per-Mandant-`User`-Zeilen** („Mitgliedschaften", jede mit eigenen Rollen). Zentralisiert werden nur **Anmeldung + MFA + Mandantenwechsel**; alles Fachliche bleibt pro Mandant. + +## 2. Getroffene Entscheidungen +| # | Entscheidung | Festlegung | +|---|---|---| +| A | MFA-Zeitpunkt | **Beim Login**, als getrennter zweiter Schritt (Two-Step, „identifier-first") | +| B | Reset-Hoheit | Mandanten-Admin verliert MFA-/Passwort-Reset; Reset via **Self-Service (Recovery-Codes) + Plattform-Ebene**. Mandanten-Admin entzieht nur die **Mitgliedschaft**. | +| C | Nutzeranlage | **Einladung/Bestätigung** als Standard (Kunden-Dashboard zwingend); Plattform-Admin darf zusätzlich direkt verknüpfen | +| D | Migration Altbestand | **Entfällt** — bisher nur Testdaten. Neuanlage/Seed statt Zusammenführung. | +| E | Plattform-Admins | **Getrennter Store** (`platform_admins`) bleibt — eigene Sicherheitsdomäne | +| + | Login-Fluss | MFA-Abfrage **erst nach** Benutzername + Passwort (siehe §5) | +| + | Passwort-Policy | **Eine globale Baseline**, passphrasen-freundlich (NIST 800-63B), mind. so streng wie der strengste Mandant | + +**Phase 2 (bewusst zurückgestellt):** per-Mandant-Schalter „bei jedem Betreten Step-up erzwingen"; E-Mail-Änderung als Identity-Operation. + +## 3. Datenmodell-Skizze (konzeptuell) +**Neu: `Identity` (global)** — die Anmelde-Identität einer Person. +- `email` (global eindeutig, Verknüpfungsschlüssel) · `passwordHash` · MFA (`mfaSecret`, `mfaEnrolledAt`, `recoveryCodes`) · `status` · `sessionsValidAfter` (globaler Kill-Switch) · Lockout-Felder. + +**`User` (bestehend, bleibt pro Mandant) = „Mitgliedschaft"** — bekommt nur ein neues Feld `identityId → Identity`. +- Behält: `tenantId`, `name`, `status`, **Rollen** (`user_roles`), **alle Ownership-FKs** (Asset-/Risk-/Prozess-Eigentümer …). +- Gibt ab (wandert auf `Identity`): `passwordHash`, MFA-Felder, Recovery-Codes → künftig **nicht mehr** für Auth genutzt. + +**Verknüpfung:** `Identity 1 —— N User(=Membership)`. Eine Person mit drei Mandanten = **eine** Identity + **drei** User-Zeilen. + +**Unverändert:** `Role`/`UserRole`/`Permission` (pro Mandant), `Tenant`, `TenantSettings` (inkl. MFA-Pflicht-Flag), `platform_admins` (separat). + +## 4. Was liegt wo? +| Aspekt | Identity (global) | Membership = User (pro Mandant) | +|---|---|---| +| Passwort / Passphrase | ✅ (eins) | — | +| MFA / Recovery-Codes | ✅ (eine Einrichtung) | — | +| Rollen & Rechte | — | ✅ (je Mandant frei verschieden) | +| Ownership (Assets, Risiken …) | — | ✅ | +| Sperre der Person (global) | ✅ `status`/`sessionsValidAfter` | — | +| Entzug des Zugangs zu **einem** Mandanten | — | ✅ Mitgliedschaft deaktivieren/löschen | + +## 5. Login-Fluss (Two-Step, MFA beim Login) +1. **Schritt 1 — E-Mail + Passwort** → Credential der `Identity` prüfen (Lockout + konstante Laufzeit gegen Enumeration wie heute). +2. **Zwischenzustand:** kurzlebiger, einzweckiger **„MFA-pending"-Token** serverseitig — erlaubt **ausschließlich** den MFA-Abschluss, **keine** App-Session. (Verhindert „halb angemeldet"-Bypass.) +3. **Schritt 2 — MFA** (eigene Seite), angezeigt wenn: Identity hat MFA **oder** ≥ 1 Mitgliedschaft in einem MFA-Pflicht-Mandanten. + - MFA vorhanden → TOTP/Passkey verifizieren. + - MFA nötig, aber nicht eingerichtet → **jetzt** einrichten (Enroll-Gate). + - Keine MFA nötig → überspringen. +4. **Volle Session** ausstellen (Identity authentifiziert + MFA erfüllt). +5. **Mandanten-Auswahl:** aktive Mitgliedschaften in aktiven Mandanten. Auswahl → Server setzt `tenantId` + Rollen. **Nur eine** Mitgliedschaft → Auswahl überspringen. + - **Sicherheitsnetz:** verlangt der gewählte Mandant MFA und ist sie (noch) nicht erfüllt → MFA vor Betreten nachziehen. + +## 6. Mandantenwechsel (ohne erneuten Login) — Sicherheitskontrollen +Zulässig und Standard, **aber nur mit diesen drei Pflicht-Kontrollen:** +1. **Server-autoritativer Kontext:** aktiver `tenantId` wird bei **jedem** Wechsel aus einer **frisch validierten Mitgliedschaft** neu abgeleitet — nie aus Client-Input. RLS `app.tenant_id` pro Transaktion daraus. +2. **Re-Validierung bei jedem Wechsel/Request:** Mitgliedschaft + Mandant + Nutzerstatus + `sessionsValidAfter` prüfen → Entzug/Sperre wirkt sofort. +3. **MFA-Netz beim Betreten** eines Pflicht-Mandanten (Backstop zu §5.5). +- Zusätzlich: **Wechsel wird auditiert** („Identity X → Mandant Y"), Folgeaktionen werden der aktiven Mitgliedschaft/Mandant zugeordnet. +- Restrisiko bewusst: breiterer Blast-Radius eines kompromittierten Credentials → beherrscht über starke Identität + MFA + kurze Session-Laufzeit + globalen Kill-Switch. + +## 7. MFA-Matrix (Person × Mandant) +| Identity hat MFA? | Zielmandant verlangt MFA? | Ergebnis beim Login/Betreten | +|---|---|---| +| ja | ja | Faktor verifizieren | +| ja | nein | kein Zwang (Faktor liegt vor, wird nicht abgefragt) | +| nein | ja | **Einrichtung erzwingen** | +| nein | nein | keine MFA | + +> Grenze: Ein Mandant kann **kein** eigenes, isoliertes MFA-Gerät erzwingen — es gibt **einen** Faktor pro Person. (Preis der zentralen Identität.) + +## 8. Nutzeranlage +**Über das Plattform-(Admin-)Dashboard:** +- E-Mail unbekannt → neue `Identity` (Initialpasswort/Einladung, `mustChangePassword`) + Mitgliedschaft im Zielmandanten mit Rollen. +- E-Mail bekannt → **kein** neues Passwort/MFA, **nur** Mitgliedschaft ergänzen. Person sieht den Mandanten künftig in der Auswahl. (Betreiber darf direkt verknüpfen.) + +**Über das Kunden-(Mandanten-)Dashboard — immer per Einladung:** +- Mandanten-Admin sieht **neutral** „Einladung an *E-Mail* gesendet" — unabhängig davon, ob die Identity schon existierte (**kein** Cross-Tenant-Leak / keine Konten-Enumeration). +- Identity existiert → Person **bestätigt** den Beitritt in ihrem bestehenden Konto (Einwilligung durch den Menschen, nicht durch den fremden Admin). +- Identity existiert nicht → normaler „Konto einrichten + beitreten"-Flow. +- Rollen werden bei der Einladung je Mandant vergeben (frei verschieden pro Mandant). + +## 9. Passwort-/Passphrasen-Policy +- **Eine globale Baseline** (weil ein Credential), mind. so streng wie der strengste Mandant. +- Passphrasen voll unterstützt: lange Obergrenze (≥ 64 Zeichen), Leer-/Unicode-Zeichen erlaubt, **keine** erzwungene Zusammensetzung, **kein** Zwangswechsel, **Abgleich gegen Leak-Listen**. Hashing wie bisher Argon2id. + +## 10. Auswirkungen auf Bestehendes +- **Zwei Auth-Instanzen bleiben** (Mandant vs. Plattform). Die Mandanten-Instanz authentifiziert künftig gegen **`Identity`** statt `User`; die Session trägt zusätzlich die **Mitgliedschaftsliste** und den **aktiven** `tenantId`. +- **RLS/Ownership/Audit unverändert** — hängen weiter an der per-Mandant-`User`-Zeile. +- **Login-UI** wird zweistufig (Passwort-Seite → MFA-Seite → Mandanten-Auswahl); die heutige „alles in einem Formular"-Maske entfällt. +- **MFA-/Passwort-Reset** in der Mandanten-Nutzerverwaltung entfällt (→ Self-Service/Plattform); dort bleibt „Mitgliedschaft deaktivieren/Rollen ändern". +- **Bootstrap/Seed** legt künftig `Identity` + Mitgliedschaft(en) an. + +## 11. Offene Detailpunkte fürs Implementierungs-Feindesign (kein Blocker) +- Genaue Lebensdauer/Signierung des „MFA-pending"-Zustands. +- Darstellung & Default der Mandanten-Auswahl (zuletzt genutzt merken?). +- Wortlaut der neutralen Einladungs-Rückmeldung + Ablauf/Frist der Einladung. +- Recovery-Code-Fluss als alleiniger Selbst-Reset-Weg (Anzahl, Nachgenerierung). diff --git a/docs/KONZEPT-incidents.md b/docs/KONZEPT-incidents.md new file mode 100644 index 0000000..4717c10 --- /dev/null +++ b/docs/KONZEPT-incidents.md @@ -0,0 +1,121 @@ +# Incident-Management — Fachkonzept (Certvia) + +Modul „Vorfälle" (Placeholder im Bestand). Umfang: **Standard** — erfassen → kategorisieren/bewerten → bearbeiten (Verantwortliche, Aufgaben, Maßnahmen) → abschließen + Lessons Learned. Rahmen: **ISO 27001** (A.5.24–5.28), **NIS2** (Meldepflicht-Bewusstsein + Fristen), **TISAX/VDA-ISA** (1.6.x). Kanäle: **intern manuell** + **E-Mail-to-Ticket**. **Keine Behörden-API** — NIS2-/DSGVO-Meldung wird **vorbereitet** (Fristen-Timer + Meldevorlage/Export), Übermittlung erfolgt manuell. + +--- + +## 1. Rollen (RACI-Kurz) +| Rolle | Aufgabe | +|---|---| +| **Melder** (intern / E-Mail) | Meldet den Verdacht/Vorfall (Titel, Beschreibung, was/wann). | +| **ISB / Incident-Manager** | Triage, Kategorisierung, Bewertung, Steuerung, **Meldepflicht-Entscheidung**, Abschluss. | +| **IT / Bearbeiter** | Sofort-/Behebungsmaßnahmen umsetzen (als Aufgaben). | +| **Geschäftsführung** | Eskalation, Freigabe externer Meldungen. | +| **DSB** (optional) | Bei Personenbezug (DSGVO Art. 33/34). | + +## 2. Kanäle (Intake) +- **Intern manuell:** berechtigte Rollen legen Vorfall über die UI an (Popup wie bei Assets/Aufgaben). +- **E-Mail-to-Ticket:** Zustellung an ein **Certvia-seitiges Eingangspostfach** (nicht an ein Kundenpostfach). Certvia betreibt eine Inbound-Domain und vergibt **je Mandant eine eindeutige, nicht erratbare Adresse** (z. B. `vorfall-@in.certvia.de`); der Kunde nutzt sie direkt **oder** leitet von seiner eigenen Adresse (`vorfall@kunde.de`) dorthin **weiter**. Über die Zieladresse erfolgt die **Mandantenzuordnung**. Eingehende Mail → Vorfall im Status **Neu/Triage** (Betreff→Titel, Text→Beschreibung, Absender→Melder). Dedupe über Message-Header; **Absender-Allowlist** (nur interne Kundendomänen erzeugen Tickets) + SPF/DKIM/DMARC-Prüfung + Spam-Filter; externe/unbekannte Absender werden „extern" markiert (Triage). Anhänge später (Storage-Paket). + - **Inbound ist ein eigener Kanal:** SEC1 deckte nur den **Ausgang** (SMTP) ab; für den Empfang braucht es einen Empfangsweg. **Warum kein Kundenpostfach:** kein Speichern/Pollen von Kunden-IMAP/OAuth-Credentials → weniger Aufwand, robuster, DSGVO-/sicherheitsseitig sauberer. + - **Konkrete Umsetzung (All-inkl · einfachster Weg, gewählt):** Subdomain **`in.certvia.de`** bei All-inkl mit **Catch-all-Postfach** — alle `vorfall-@in.certvia.de` landen in **einem** Postfach. *(Catch-all in All-inkl KAS: E-Mail → E-Mail-Postfach → „Neues Postfach anlegen", das **Adressfeld leer lassen**. Catch-all ist spam-anfällig → eigene, nirgends veröffentlichte Intake-Subdomain hält die Spam-Fläche klein; zusätzlich Allowlist/DKIM/Review-Pfad.)* Certvia holt die Mails per **IMAP** (kurzes Polling/IDLE, BullMQ-Job), parst sie (mailparser), ermittelt den **Token aus dem Empfänger-Header** (`Delivered-To`/`X-Envelope-To` — **nicht** `To`, da dort bei Weiterleitung die Kundenadresse steht), ordnet dem Mandanten zu, legt den Vorfall an und verschiebt die Mail nach „Verarbeitet"/„Fehler". Idempotenz über `Message-ID`; unbekannter/kein Token → **Betreiber-Review** statt Drop. **Kein Postfach je Kunde** (Catch-all + **Auto-Token**), keine KAS-API nötig; einmaliger globaler Setup (Subdomain + Catch-all + IMAP-Zugang als Plattform-Secret). + - **Weiterleitungs-Fallstricke:** Weiterleitung bricht i. d. R. **SPF** (DKIM bleibt meist gültig) → **nicht** hart auf SPF-Fail ablehnen; Vertrauen über **Absender-Allowlist + DKIM**, SPF nur als Signal. Auto-Reply/Bounce-Schleifen über `Auto-Submitted`/Precedence-Header erkennen und ignorieren. Größenlimit/Spam-Filter beachten. +- **Mail-Einstellungen:** die **mandantenspezifischen** Einstellungen (Intake-Adresse/Routing, Benachrichtigungspräferenzen, Absender-Anzeige) werden im **Einstellungs-Modul** gepflegt. Die **SMTP-Zugangsdaten/der Transport** bleiben aus Sicherheitsgründen auf **Plattform-/Secret-Store-Ebene** (SEC1) — kein Mandant legt Server-Credentials selbst an. + +## 3. Lebenszyklus / Statusmodell +**Primärfluss:** +`Neu/Eingegangen → Triage → In Bearbeitung → Eingedämmt (contained) → Behoben → Abgeschlossen` · (+ `Wiedereröffnet`) +- Jeder Übergang: Pflichtfelder-Check, Zeitstempel, Akteur, Audit-Eintrag. +- **Parallel-Track „Meldung"** (nur wenn meldepflichtig): `Meldepflicht geprüft → Erstmeldung (24 h) → Folgemeldung (72 h) → Abschlussbericht (1 Monat)` — als **Status + Timer**, Übermittlung manuell. + +## 4. Datenmodell (Incident-Objekt) +- **Kennung:** `refNo` (z. B. `INC-2026-0042`), `tenantId` (RLS). +- **Basis:** Titel, Beschreibung, **Kanal/Quelle** (manuell/E-Mail), Melder (+Kontakt). +- **Zeiten:** `occurredAt` (Eintritt), `detectedAt` (Entdeckung), `reportedAt` (interne Meldung), Timeline. +- **Kategorie** (Taxonomie): Schadsoftware · Phishing/Social Engineering · Unbefugter Zugriff · Datenabfluss/-verlust · Systemausfall/Verfügbarkeit · Physisch (Zutritt/Diebstahl) · Fehlbedienung/Konfiguration · Lieferant/Drittpartei · **Prototyp/Kundendaten** (TISAX) · Sonstiges. +- **Betroffenheit:** verknüpfte **Assets/Prozesse (BIA)**, Schutzziel-Impact **C/I/A**, Datenkategorien, **Personenbezug** (→ DSGVO-Flag), **Prototyp/Kundendaten** (→ TISAX-Flag). +- **Bewertung:** **Schweregrad/Priorität** (siehe §5). +- **Steuerung:** `owner` (Incident-Manager), Bearbeiter, Status. +- **Meldepflicht:** `nis2Relevant`, `dsgvoRelevant` (bool) + Meldestatus + Fristen (§6). +- **Behebung:** Sofortmaßnahmen, **Ursache (Root Cause)**, Lösung/Resolution. +- **Abschluss:** Abschlussnotiz, **Lessons Learned**, verknüpfte **CAPA-Aufgaben**. +- **Verknüpfungen:** **Maßnahmen** (im zentralen Maßnahmen-Modul, §9), **Risiken** (bestätigt/neu), **Controls** (welche versagten/betroffen), **Nachweise**. +- **Kommentare/Notizen:** **Kommentar-Thread** am Vorfall (Autor, Zeitstempel, editierbar nach Regel) für die Zusammenarbeit — **getrennt** von der automatischen, manipulationssicheren **Audit-Timeline** (§8/§9). Interne vs. sichtbare Kommentare optional. +- **Anhänge:** Belege (Screenshots/Logs) — Modell vorbereiten, Datei-Persistenz mit Storage-Paket. + +## 5. Schweregrad / Priorisierung +- **Schweregrad** aus **Auswirkung** (C/I/A-Verletzung × Umfang: einzelnes System … unternehmensweit … Kunde/Lieferkette) und **Dringlichkeit** → Klassen **niedrig · mittel · hoch · kritisch**. +- Treibt **interne SLA** (Reaktion/Behebung), **Eskalation** und **Benachrichtigungen**. Matrix mandantenkonfigurierbar (Default vorgegeben). + +## 6. Fristen & Timer (vorbereitet, ohne Behörden-API) +| Auslöser | Frist | Umsetzung im Tool | +|---|---|---| +| **NIS2** – Früh-/Erstmeldung | **24 h** ab Kenntnis | Timer/Countdown + Erinnerung (SEC1) + Meldevorlage | +| **NIS2** – Meldung | **72 h** | Timer + Vorlage (Aktualisierung) | +| **NIS2** – Abschlussbericht | **1 Monat** | Timer + Abschluss-Vorlage/Export | +| **DSGVO** Art. 33 (bei Personenbezug) | **72 h** | Timer + Datenschutz-Meldevorlage | +| **Interne SLA** (je Severity) | konfigurierbar | Reaktions-/Behebungs-Timer | +- Timer nur, wenn **Meldepflicht = ja** (NIS2-Betroffenheit des Mandanten aus den Einstellungen). Countdown im Vorfall + Dashboard-Kachel; **Eskalation** bei drohender/verpasster Frist. **Übermittlung an die Behörde erfolgt manuell** (Vorlage/Export bereitgestellt). + +## 7. Benachrichtigungen (SEC1) +Neuer Vorfall → ISB/Incident-Manager; Zuweisung → Bearbeiter; Statuswechsel → Beteiligte; **Fristen-Erinnerung/Eskalation**; Abschluss → Melder/GF. Respektiert Benachrichtigungspräferenzen + Mandantenisolation. + +## 8. Abschluss & Lessons Learned +- Pflicht beim Abschluss: **Ursache**, **Lösung**, Wirksamkeit der Maßnahmen, **Lessons Learned**. +- **CAPA**: korrigierende/präventive Maßnahmen als **Aufgaben** anlegen; **Risikoregister** aktualisieren (Risiko bestätigt/neu); Bezug zu betroffenen **Controls**. +- Optionaler **Post-Incident-Review** (Kurzbericht) → speist **Management-Review**. + +## 9. Verknüpfung zu bestehenden Modulen +- **Maßnahmen-Modul** (vorhanden): Sofort- und CAPA-Maßnahmen werden **im zentralen Maßnahmen-Modul angelegt/gepflegt** (nicht doppelt im Vorfall) und mit dem Vorfall **verknüpft**; im Vorfall erscheinen sie als verknüpfte Liste mit „Maßnahme direkt aus dem Vorfall anlegen". Verantwortliche/Fristen/Status kommen aus dem Maßnahmen-Modul; Bezug zu Risiken/Controls möglich. *(Hinweis: falls „Maßnahmen"/„Aufgaben" heute getrennt sind, an **eine** zentrale Maßnahmen-/Aufgaben-Backbone andocken.)* +- **Kommentare** dagegen liegen **am Vorfall** (Thread, §4) — sie sind Zusammenarbeit, keine trackbare Maßnahme. +- **Assets/BIA · Risiken · Controls**: Betroffenheit und Wirkung verknüpfen; Vorfall kann Risiko bestätigen/erzeugen. +- **Audit-Log**: Vorfall-Timeline (wer/wann/was) manipulationssicher (getrennt von den Kommentaren). +- **Nachweise/Export**: Vorfallregister + Einzelbericht (DOCX/PDF über Export-Layer), NIS2-/DSGVO-Meldevorlagen (vorbefüllt) für die manuelle Übermittlung. + +## 10. Framework-Mapping +| Rahmen | Bezug | +|---|---| +| **ISO 27001:2022** | A.5.24 Planung/Vorbereitung · A.5.25 Bewertung/Entscheidung · A.5.26 Reaktion · A.5.27 Lernen · A.5.28 Beweissicherung | +| **TISAX / VDA-ISA** | 1.6.x Incident-/Ereignismanagement; Prototyp-/Kundendaten-Bezug | +| **NIS2** (Art. 23) | Meldekette 24 h/72 h/1 Monat — im Tool als Timer/Vorlage vorbereitet | +| **DSGVO** | Art. 33/34 Datenpanne (72 h) — Timer/Vorlage | + +## 11. Rechte / Sicherheit +- Strikt **mandantengebunden (RLS)**; rollenbasierte Rechte (melden vs. bearbeiten vs. abschließen/melden). +- **Vertraulichkeit:** sensible Vorfälle optional auf einen eingeschränkten Personenkreis begrenzbar. +- Meldevorlagen/Exports datensparsam; jede Aktion auditiert. + +## 12. Technische Einordnung +- **Eigenes Modul „Vorfälle"** (`incidents`), modul-gated (Superadmin-Toggle); **Maßnahmen** über das zentrale **Maßnahmen-Modul** (verknüpft); **Kommentare** als eigener Thread am Vorfall; **Mail** über SEC1; **Timeline** über Audit; Verknüpfungen zu Assets/Risiken/Controls. +- **Mail-Einstellungen:** mandantenseitig im **Einstellungs-Modul** (Intake-Adresse, Benachrichtigungen); SMTP-Transport plattformseitig (SEC1). +- Popups/Bedienung im etablierten Muster (wie Assets/Maßnahmen). + +## 12a. Provisionierung des Intake-Postfachs (Betreiberportal & Onboarding) +Das Anlegen der Inbound-Route (`vorfall-@in.certvia.de`) ist zunächst ein **manueller Betreiber-Schritt** — dafür braucht es die richtigen Infos beim Onboarding und einen sichtbaren Status. + +**Beim Kunden-Onboarding erfassen** (Admin-Konsole „Kunde anlegen", nur wenn Modul „Vorfälle" + E-Mail-to-Ticket aktiv): +- **Absender-/Weiterleitungs-Domäne(n)** des Kunden (z. B. `kunde.de`) → **Allowlist**. +- optional konkrete **Quelladresse** (`vorfall@kunde.de`), von der weitergeleitet wird. +- **Intake-Adresse** wird von Certvia **automatisch generiert** (`vorfall-@in.certvia.de`) und angezeigt (der Kunde richtet die Weiterleitung darauf ein). +- optional Benachrichtigungsempfänger/Sprache. + +**Provisionierungs-Status je Kunde** (Betreiberportal): `Postfach anzulegen → angelegt → verifiziert`. +- Solange „anzulegen": **Hinweis-Badge** am Kundendatensatz („⚠ Intake-Postfach anlegen") **und** eine **Sammelliste offener Provisionierungen** auf dem Betreiber-Dashboard. +- **Betreiber-Schritt:** Inbound-Route/Alias im Inbound-Dienst anlegen (manuell **oder** per Provider-API) → Status „angelegt". **Verifizierung** per Test-Mail (analog SEC1-Testversand) → „verifiziert". +- **Ausbau:** bei Inbound-Providern mit API kann die Route beim Modul-Aktivieren **automatisch** angelegt werden → Status springt direkt auf „angelegt"; bis dahin bleibt es der manuelle Hinweis-Schritt. +- Alle Provisionierungs-Aktionen im **Plattform-Audit** (`scope=platform`). + +> **Mit der gewählten Variante (All-inkl Catch-all + Auto-Token):** Es muss **kein Postfach je Kunde** angelegt werden; der **Token wird automatisch generiert**. Der einmalige Setup (Subdomain `in.certvia.de` + Catch-all-Postfach + IMAP-Zugang) ist ein **globaler** Betreiber-Schritt, nicht je Kunde. Der **per-Kunde-Schritt reduziert sich** darauf, die **Weiterleitung des Kunden per Test-Mail zu verifizieren** → vereinfachter Status je Kunde: `Weiterleitung ausstehend → verifiziert`. Der Onboarding-Datenbedarf bleibt (Allowlist-Domänen, Quelladresse); die Intake-Adresse wird automatisch erzeugt/angezeigt. + +## 13. Abgrenzung / spätere Ausbaustufen +- **Direkte Behörden-Übermittlung** (BSI-Meldeportal/-API) — jetzt bewusst **nicht** (nur Vorlage/Export). +- Automatische Erkennung/**SIEM-Integration**, **externe/anonyme** Meldung, SLA-Automationen, KI-gestützte Klassif/Zusammenfassung — spätere Stufen. + +## 14. Offene Entscheidungen +1. **NIS2-Betroffenheit je Mandant** — woher (Mandanten-Einstellungen: „wichtige/wesentliche Einrichtung"?), steuert die Timer. +2. **Severity-Matrix** — fester Default oder mandantenkonfigurierbar? +3. **Inbound (entschieden):** All-inkl **Catch-all-Postfach** auf `in.certvia.de` + **IMAP-Abholung**, **Auto-Token**, kein Postfach je Kunde. Rest-Details: Polling-Intervall vs. IMAP-IDLE, welcher Header trägt den Token (`Delivered-To`/`X-Envelope-To` — beim ersten Test verifizieren), Ordner-/Fehler-Handling. +4. **Anhänge** — abhängig vom Storage-Paket (bis dahin nur Referenz/Text). +5. **Vertraulichkeits-Stufen** für sensible Vorfälle — jetzt oder später? + +--- +*Nächster Schritt auf Wunsch: Entwickler-Task-Paket (Branches, Stories, DoD) — Maßnahmen auf das Task-Modul aufsetzend, Mail über SEC1, Timer/Meldevorlagen NIS2/DSGVO.* diff --git a/docs/KONZEPT-ui-i18n.md b/docs/KONZEPT-ui-i18n.md new file mode 100644 index 0000000..fa9c5a5 --- /dev/null +++ b/docs/KONZEPT-ui-i18n.md @@ -0,0 +1,50 @@ +# Konzept — Betreiber-Konsole-UX + vollständige i18n (parallele Lane) + +> Status: **Backlog/Feindesign-Skizze** (kein Code). Produkt: **certvia** (ISMS-Tool). Unabhängig von Identity/Backup/Härtung → **parallel** abarbeitbar. Enthält die zwei gemeldeten „Bugfixes" + zwei kleine Ergänzungen. + +## Bugfix 1 — Betreiber-Konsole: Module & Benutzer als Popup, Stammdaten sichtbar +**Betrifft:** `src/app/(platform)/admin/[id]/page.tsx` (Mandanten-Detailseite im Betreiber-Portal). + +**Ist:** Module-Liste und Benutzerverwaltung liegen **inline direkt auf dem Kundenprofil**; die eigentlichen Stammdaten des Kunden sind dort **nicht** prominent. + +**Soll:** +- **Module → Popup:** nicht mehr inline, sondern per Button „Module verwalten" → Popup (Muster wie gehabt über searchParam, z. B. `?modules=1`, ``). Toggle/Import bleiben im Popup. +- **Benutzer → Popup:** die Benutzer-Tabelle/-Verwaltung nicht mehr im Hauptfenster, sondern Button „Benutzer verwalten" → Popup (`?users=1`). Anlage/Bearbeiten laufen wie bisher als verschachtelte Modals (`?new`/`?edit`). +- **Hauptfenster stattdessen:** **Stammdaten** (aus `TenantSettings`: Unternehmensname/Kurzname, Adresse, Sektor, D-U-N-S, TISAX-Level, Status) **+ Hauptkontakt** prominent sichtbar. „Hauptkontakt" = neues/abgeleitetes Feld (z. B. designierter Mandanten-Admin oder ein Stammdaten-Kontaktfeld) — **offene Kleinentscheidung:** eigenes Feld in `TenantSettings` (`mainContactName/Email/Phone`) vs. Ableitung aus dem `tenant-admin`. + +**Muster ist vorhanden:** die Seite nutzt bereits `` + searchParams (`?new`/`?edit`/`?audit`) → Module/Benutzer analog kapseln, keine neue Infrastruktur. + +**Dateien:** `src/app/(platform)/admin/[id]/page.tsx`, ggf. `src/components/*` (Auslagerung Module-/Benutzer-Block), optional Migration für `mainContact*` in `TenantSettings`. + +## Bugfix 2 — Vollständige UI-Sprache (Menü + Beschreibungen) + per-Mitarbeiter-Umschaltung +**Wichtiger Befund:** Der **englische UI-Katalog existiert bereits** (`messages/en.json`, ~95 % vs. `messages/de.json`). Bisher ist **nur der Richtlinien-Inhalt** EN (über `TenantSettings.locale`, das die **Import-Sprache der Vorlagen** steuert). Das **Menü/die Beschreibungen** sind EN im Katalog vorhanden, werden aber **nie angezeigt**, weil: +``` +src/i18n/request.ts:8 → const locale = "de"; // hart verdrahtet +// Kommentar: "MVP is fixed to de; per-user locale (en) is prepared — switch here later" +``` + +**Soll:** die UI-Sprache **per Mitarbeiter individuell** umschaltbar. +- **Speicherort (Option-C-konform):** persönliche Präferenz gehört an die **`Identity`** (folgt der Person über alle Mandanten) — neues Feld `Identity.uiLocale` (`de`|`en`, Default `de`). *(Alternative: pro Mitgliedschaft — verworfen, weil Menüsprache eine Personen-, keine Mandantenpräferenz ist.)* +- **Aktivierung:** `src/i18n/request.ts` liest statt der Konstante die `uiLocale` der aktiven Session-Identity (Fallback `de`). +- **Umschalter:** im **Nutzer-Menü** (Header/Profil) ein Sprachauswahl-Control → Server-Action `setUiLocale` → `Identity.uiLocale` speichern, Seite neu laden. +- **Restsprache:** `messages/en.json` auf 100 % prüfen/auffüllen (Lücken, neue Strings aus TISAX/Identity-Umbau). Sicherstellen, dass **alle** sichtbaren Strings über den Katalog laufen (keine hartkodierten deutschen Texte in Komponenten). + +**Abgrenzung:** `TenantSettings.locale` bleibt für die **Vorlagen-Import-Sprache** (Inhalt); **neu** ist die **UI-Sprache je Person** (`Identity.uiLocale`) — zwei getrennte Achsen. + +**Dateien:** `prisma/schema.prisma` (`Identity.uiLocale` + Migration), `src/i18n/request.ts`, Nutzer-Menü-Komponente (Header/Profil) + `setUiLocale`-Action, `messages/en.json` (Lückenschluss), Audit der hartkodierten Strings. + +## Ergänzung A — Login-Maske: Organisationsfeld entfällt +**Ist:** `src/app/login/page.tsx` zeigt weiterhin ein optionales Feld **„Organisation"** (`tenant`, als Hinweis behalten). +**Soll:** Feld **entfernen** — nach Option C ist es überflüssig (Login gegen globale Identity; Mandant wird **nach** dem Login über `/select-tenant` gewählt). Die `tenant`-Durchreichung in `login`-Action / `signMfaPending` / `signLoginTicket` kann entfallen bzw. leer bleiben. +**Dateien:** `src/app/login/page.tsx` (Feld raus), ggf. `src/server/login-ticket.ts`-Signaturen entschlacken. + +## Ergänzung B — Konsistenz-Check „Stammdaten" +Beim Sichtbarmachen der Stammdaten (Bugfix 1) prüfen, dass die Quelle **eine** bleibt (`TenantSettings` speist die ISMS-Variablen) — keine Doppelpflege einführen. + +## Reihenfolge / Parallelität +- **Bugfix 1** (Betreiber-Konsole) und **Bugfix 2** (i18n) sind unabhängig → parallel. +- **Ergänzung A** (Login) ist ein 10-Minuten-Fix, gern zusammen mit Bugfix 2 (beide Auth-/UI-nah). +- Keine Abhängigkeit zu Backup/Härtung; Bezug zu Option C nur konzeptuell (`Identity.uiLocale`, `/select-tenant` existiert bereits). + +## Gate (wie immer) +tsc/lint/build + `scripts/test-*.ts` grün; UI-Änderungen im Browser verifizieren (Betreiber-Popups, Sprachumschaltung DE↔EN, Login ohne Organisationsfeld). diff --git a/docs/MOCKUP-bia-prozessuebersicht.html b/docs/MOCKUP-bia-prozessuebersicht.html new file mode 100644 index 0000000..b37f48f --- /dev/null +++ b/docs/MOCKUP-bia-prozessuebersicht.html @@ -0,0 +1,355 @@ + + + + + +certvia – BIA-Prozessübersicht (Mockup) + + + + + + +
+ +
+
+
Strukturanalyse · GEFIM (TISAX)
+

Business Impact Analyse — Prozessübersicht

+
Prozesse gegliedert nach Haupt- und Teilprozessen. Farbe = BIA-Status, Kritikalität nach Maximumprinzip aus den Teilprozessen abgeleitet. Abhängigkeiten zeigen, welche Prozesse voneinander bzw. von gemeinsamen Diensten abhängen.
+
+
+
+ + +
+ +
+
+ + +
+
Prozesse gesamt
24 / 6 Haupt
+
Im Scope
21 / 24
+
BIA vollständig
13 / 21
+
Kritische Prozesse
4
+
+ + +
+
BIA-Status:
+
komplett
+
teilweise
+
offen
+
Kritikalität:
+
1 niedrig
+
2 mittel
+
3 hoch
+
4 kritisch
+
+ + +
+
Managementprozesse1 Hauptprozess · 3 Teilprozesse
+ +
+ + +
+
Unternehmenssteuerung & ISMS Management
+
+ GF M. Geschäftsführung + ·3 Teilprozesse +
+
+
+
RTO
24 h
+
RPO
24 h
+
MTD
72 h
+
+ Krit. 2 + teilweise +
+ +
+ ↳ benötigt: + IT-Betrieb + Personalmanagement +
+ +
+
Teilprozesse
+
+ +
Risikomanagement
Owner: ISBSchnittstelle: Risiko-Modul
+
RTO
48 h
RPO
24 h
MTD
1 W
+
Krit. 2
+
+
+ +
Interne Audits
Owner: ISB
+
RTO
1 W
RPO
1 W
MTD
2 W
+
Krit. 1
+
+
+ +
Managementbewertung
Owner: GFBIA offen
+
RTO
—
RPO
—
MTD
—
+
BIA erfassen →
+
+
+
+
+ + +
+
Kernprozesse2 Hauptprozesse · 8 Teilprozesse
+ +
+ + +
+
Produktentwicklung / Engineering Kern
+
HE H. Entwicklung·4 Teilprozesse
+
+
+
RTO
8 h
+
RPO
4 h
+
MTD
24 h
+
+ Krit. 4 + komplett +
+ +
+ ↳ benötigt: + IT-Betrieb · CAD-Systeme + Einkauf · Musterteile + ◆ Prototypenschutz +
+ +
+
Teilprozesse
+
Konstruktion (CAD)
Owner: H. EntwicklungAssets: CAD-Server, PLM
RTO
8 h
RPO
4 h
MTD
24 h
Krit. 4
+
Prototypenbau
Owner: Werkstattleitung◆ Prototypenschutz
RTO
1 T
RPO
8 h
MTD
3 T
Krit. 3
+
Anforderungsmanagement
Owner: Projektleitung
RTO
2 T
RPO
1 T
MTD
1 W
Krit. 2
+
Erprobung & Test
Owner: QS
RTO
2 T
RPO
1 T
MTD
1 W
Krit. 2
+
+
+ +
+ + +
+
Auftragsabwicklung Kern
+
VL Vertriebsleitung·4 Teilprozesse
+
+
+
RTO
4 h
+
RPO
1 h
+
MTD
24 h
+
+ Krit. 4 + teilweise +
+
+ ↳ benötigt: + IT-Betrieb · ERP + Einkauf & Lieferanten +
+
+
Teilprozesse
+
Fertigung
Owner: ProduktionsleitungAssets: MES, Maschinen
RTO
4 h
RPO
1 h
MTD
24 h
Krit. 4
+
Produktionsplanung
Owner: Arbeitsvorbereitung
RTO
8 h
RPO
4 h
MTD
2 T
Krit. 3
+
Versand & Logistik
Owner: Logistik
RTO
1 T
RPO
8 h
MTD
3 T
Krit. 2
+
Angebot & Kalkulation
Owner: VertriebBIA offen
RTO
—
RPO
—
MTD
—
BIA erfassen →
+
+
+
+ + +
+
Unterstützende Prozesse3 Hauptprozesse · 8 Teilprozesse
+ +
+ + +
+
IT-Betrieb Support ▲ 3 Prozesse hängen hiervon ab
+
IT IT-Leitung·4 Teilprozesse
+
+
+
RTO
4 h
+
RPO
1 h
+
MTD
24 h
+
+ Krit. 4 + komplett +
+
+ ▲ wird benötigt von: + Produktentwicklung + Auftragsabwicklung + Unternehmenssteuerung +
+
+
Teilprozesse
+
Netzwerk & Infrastruktur
Owner: NetzwerkadminAssets: Core-Switch, FW
RTO
4 h
RPO
1 h
MTD
24 h
Krit. 4
+
Backup & Recovery
Owner: IT-BetriebVA-08
RTO
8 h
RPO
1 h
MTD
24 h
Krit. 4
+
Client-/Server-Betrieb
Owner: IT-Betrieb
RTO
8 h
RPO
4 h
MTD
2 T
Krit. 3
+
Berechtigungsverwaltung
Owner: IT + ISB
RTO
1 T
RPO
8 h
MTD
3 T
Krit. 3
+
+
+ +
+ + +
+
Einkauf & Lieferantenmanagement Support
+
EK Einkaufsleitung·2 Teilprozesse·BIA offen
+
+
+
RTO
—
+
RPO
—
+
MTD
—
+
+ offen + offen +
+
+
Teilprozesse
+
Lieferantenauswahl
Owner: EinkaufBIA offen
RTO
—
RPO
—
MTD
—
BIA erfassen →
+
Wareneingang / QS
Owner: QSBIA offen
RTO
—
RPO
—
MTD
—
BIA erfassen →
+
+
+
+ +
+ Was ist neu ggü. der heutigen Ansicht? Statt einer flachen Tabelle aller Prozesse werden sie nach Prozesskategorie (Management / Kern / Support) gruppiert und in Haupt- → Teilprozesse aufgeklappt. Jeder Hauptprozess rollt Kritikalität (Maximumprinzip) und die schärfsten RTO/RPO/MTD-Werte seiner Teilprozesse zusammen. Abhängigkeiten („↳ benötigt" / „▲ wird benötigt von") machen sichtbar, welche Prozesse auf gemeinsame Dienste wie den IT-Betrieb angewiesen sind — ein Ausfall dort trifft alle abhängigen Prozesse. Datenbasis ist bereits vorhanden (Process.parentId, category, biaStatus, BiaEntry); es ist reine Darstellung, kein Datenmodell-Umbau. +
+
Mockup · certvia BIA-Prozessübersicht · Beispieldaten (GEFIM) · nicht verbindlich
+ +
+ + diff --git a/docs/ONBOARDING-AGENT.md b/docs/ONBOARDING-AGENT.md new file mode 100644 index 0000000..ca63f4a --- /dev/null +++ b/docs/ONBOARDING-AGENT.md @@ -0,0 +1,67 @@ +# Onboarding-Prompt für einen neuen Claude-Code-Agenten + +> Diesen Prompt dem neuen Agenten als erste Nachricht geben. Er enthält bewusst **keinen** +> inhaltlichen Projektstand — der steht in `docs/STAND-dev-branch.md` und wird nur dort +> gepflegt (kein doppelter, veraltender Stand im Prompt). + +--- + +```text +Du übernimmst die Weiterentwicklung des ISMS-Tools (Multi-Tenant-SaaS für +ISO 27001:2022 / TISAX / VDA-ISA 2027). Mach dich zuerst mit dem Stand vertraut. +Beginne noch KEINE Aufgabe — lies ein, bestätige dein Verständnis und warte dann +auf meine Anweisung. + +## Repo & Umgebung +- Arbeitsverzeichnis: das lokale Repo `ISMS-Tool` (kein Gitea-/Remote-Zugang!). +- Du kannst NICHT pushen. Arbeite auf Branch `dev`, committe lokal. Pushen mache ich selbst. + Prüfe mit `git branch --show-current`, dass du auf `dev` bist (NICHT `main`). +- Stack: Next.js 16 (App Router, Turbopack, Server Actions), React 19, TypeScript strict, + Prisma 7 (+ @prisma/adapter-pg), PostgreSQL + pgvector, NextAuth v5, Tailwind. + +## Zuerst lesen (in dieser Reihenfolge) — das ist die maßgebliche Statusquelle +1. `docs/STAND-dev-branch.md` — konsolidierter Gesamtstand (PM + Technik): was fertig/offen + ist, wo was liegt, Datenmodelle, Migrationen, Fallstricke, Demo-Logins. +2. `docs/HANDOVER-DEV.md` — Setup, Stack, Konventionen, Migrations-Flow (§1–§10). +3. `docs/SPEC.md` — fachliche Spezifikation. +Verlasse dich auf diese Dokumente statt zu raten. Den inhaltlichen Projektstand NICHT aus +diesem Prompt ableiten — er steht ausschließlich in der Doku (Single Source of Truth). + +## Arbeitskonventionen (verbindlich) +- Commits auf Deutsch, granular pro Thema, mit Trailer: + `Co-Authored-By: Claude Opus 4.8 ` +- Neue mutierende Server-Action → über `moduleGuard("")` und in + `scripts/check-module-guards.ts` eintragen (sonst failt der Build). +- Neue mandantengebundene Prisma-Modelle → in `TENANT_MODELS` (`src/server/db.ts`) + UND RLS-Policy in der Migration (`tenant_isolation` via `current_setting('app.tenant_id')`). +- Migrations-Flow Prisma 7: + `npx prisma migrate diff --from-config-datasource prisma.config.ts --to-schema prisma/schema.prisma --script` + → RLS-DO-Block manuell anhängen → `npx prisma migrate deploy` → `npx prisma generate`. + (tsx-Skripte brauchen `import "dotenv/config"`.) +- Zentrale Richtlinien-Variablen (Organisation/Rollen/Schutzbedarf) sind nur in `/settings` + pflegbar und serverseitig geschützt — nicht im Richtlinien-Editor. +- Editier-UIs immer als Popup/Modal (Muster: Assets/Lieferanten/Software/Projekte). +- Doku mitpflegen: Nach jeder abgeschlossenen Arbeit `docs/STAND-dev-branch.md` + aktualisieren (Executive Summary, PM-Statustabelle, ggf. neue Modelle/Migrationen, + „Wo liegt was", Commit-Übersicht, offene Punkte). Das ist die Single Source of Truth — + sie muss den `dev`-Stand jederzeit korrekt widerspiegeln. Der Doku-Update gehört in einen + eigenen Commit (oder denselben Themen-Commit), nicht separat vergessen. + +## Jede Iteration abschließen mit +`npx tsc --noEmit` → `npm run lint` → `npm run build` (führt `prebuild`-Guard-Check aus). +Bei Änderungen am Vorlagenpaket zusätzlich `python3 seed/isms-vorlagenpaket-v2/_verify.py` +(muss `OK` liefern). Wo im Browser sichtbar: Dev-Server (`npm run dev`, Port 3000) und selbst +verifizieren — nicht den Nutzer manuell prüfen lassen. Hinweis: geänderte Server-Actions +greifen im Turbopack-Dev teils erst nach Neustart des Dev-Servers. Voraussetzung: lokale +Postgres-DB läuft und `.env` mit `DATABASE_URL` ist vorhanden (siehe HANDOVER-DEV.md). + +## Lokale Demo-Daten +Seed: `npx tsx prisma/seed.ts` (idempotent). Demo-Logins Passwort `Demo1234!`: +`admin@demo.example` (Mandanten-Admin+ISB), `bea.approver@demo.example` (2. Freigeber für +Vier-Augen), `auditor@`, `owner@`, `user@`. Plattform-Login unter `/platform/login`. + +## Ablauf jetzt +Lies die drei Dokumente, fasse mir in wenigen Sätzen zusammen, was der aktuelle Stand ist +und was als Nächstes offen wäre, und WARTE dann auf meine konkrete Aufgabe. Fang nichts +Eigenes an. Bei Unklarheiten: gezielt nachfragen. +``` diff --git a/docs/PROMPT-lane-backup-target.md b/docs/PROMPT-lane-backup-target.md new file mode 100644 index 0000000..da6f563 --- /dev/null +++ b/docs/PROMPT-lane-backup-target.md @@ -0,0 +1,59 @@ +# Kickoff-Prompt — Lane Konfigurierbarer Backup-Zielspeicher (certvia) + +> Diesem Prompt einem Entwickler/Claude-Code-Agenten geben. Bootstrapt in certvia + diese Lane. + +```text +Du übernimmst die Lane „Konfigurierbarer Backup-Zielspeicher" am Produkt „certvia" (ISMS-Tool, +Multi-Tenant Next.js-16 / Prisma-7 / Postgres+RLS / Auth.js-v5). Repo: ~/Projects/ISMS-Tool, Branch `dev`. + +WICHTIG: certvia ist strikt getrennt von jedem anderen Produkt (insb. „visitvia"). Nichts vermischen. + +BRANCH/CHECKOUT: + Arbeits-Branch: `lane-backup-target` (KEIN `feature/`-Prefix — origin-Namespace-Konflikt). + git fetch origin && git checkout dev && git checkout -b lane-backup-target. + Remotes: origin = https://git.certvia.de/msolarczek/certvia.git · local-gitea (intern). + +1) PFLICHTLEKTÜRE: + - docs/HANDOVER-DEV.md, docs/SPEC.md, docs/STAND-dev-branch.md + - docs/KONZEPT-backup-target.md ← dein Fahrplan + - docs/KONZEPT-backup-restore.md §9 ← Verschlüsselung/Secrets-Kohärenz + - Bestand ansehen: src/server/storage/backup-store.ts (BackupStore, S3-/Local-Store, createBackupStore) + +2) AUFTRAG: + Den Backup-Zielspeicher im Betreiber-Portal konfigurierbar machen + lokale (persistente) Option. + a) DATENMODELL: PlatformSetting erweitern (backupTarget local|s3, backupLocalDir, backupS3Endpoint/ + Bucket/Region/AccessKey, backupS3SecretKeyEnc). Additive Migration (nullable, Default local). + b) FACTORY: statisches `backupStore` → `getBackupStore(): Promise`, liest PlatformSetting, + entschlüsselt den S3-Key (secret-crypto). Präzedenz DB → Env (S3_*/BACKUP_LOCAL_DIR) → lokaler + Default `.backups`. Cachen + bei Settings-Änderung invalidieren. Die 3 Nutzer umstellen: + src/server/backup/export.ts, restore.ts, ops.ts. + c) UI: Seite im Plattform-Portal (z. B. /admin/backup): Ziel wählen (Lokal/S3), Config, „Verbindung + testen" (Probe put/get/remove). Gated requirePlatformFullAdmin + MFA-Step-up. Speichern via Action + analog setPlatformMfaRequired (platformSetting.upsert); S3-Secret VOR dem Schreiben verschlüsseln. + d) PERSISTENZ: docker-compose.coolify.yml — persistentes Volume `backups:` (wie pgdata/miniodata) in + app+worker mounten (Pfad = backupLocalDir, z. B. /app/.backups). + e) TESTS: scripts/test-backup-* erweitern (Store-Auflösung DB local/s3, Präzedenz, Test-Verbindung, + fail-secure bei unvollständiger S3-Config, Export→Restore gegen beide Backends). + +3) VERBINDLICHE REGELN: + - S3-Secret NUR verschlüsselt in der DB (src/server/secret-crypto.ts: encryptSecret/decryptSecret) — nie Klartext. + - Fail-secure: backupTarget=s3 mit unvollständiger Config → klarer Fehler, NICHT still auf lokal fallen. + - Env-Fallback erhalten (Rückwärtskompatibilität bestehender Deployments). + - BACKUP_ENC_KEY (Artefakt-Verschlüsselung) bleibt GETRENNT vom Zielspeicher — nicht vermischen. + - RLS/Mandanten-Isolation der Artefakt-Keys (`/backups/…`) unverändert lassen. + - Config-Bearbeitung nur Full-Admin + Step-up, auditiert. + +4) ARBEITSWEISE: + - Gate vor JEDEM Merge: npx tsc --noEmit · npm run lint · npm run build · ALLE scripts/test-*.ts. + - migrate reset gegen lokale DB braucht Nutzer-Zustimmung (Prisma-Guard). + - UI im Browser verifizieren: Ziel umschalten Lokal↔S3, „Verbindung testen", Export→Restore lokal. + - DevOps: lane-backup-target → git merge --no-ff nach dev → Gate grün → Push auf BEIDE Remotes → + docs/STAND-dev-branch.md pflegen. + +5) NICHT TUN: kein Umbau am Auth-/RLS-Kern; keine Mehrfachziele/Offsite-Profile (Phase 2); Artefakt- + Verschlüsselung (crypto.ts) nicht anfassen. + +Erste Schritte: (a) Pflichtlektüre + backup-store.ts lesen, 10-Zeilen-Zusammenfassung + Fragen, +(b) PR-Plan (Schema+Migration, getBackupStore-Refactor, UI, Compose-Volume, Tests), (c) nach Freigabe +umsetzen. Warte nach (a)/(b) auf Bestätigung. +``` diff --git a/docs/PROMPT-lane-backup.md b/docs/PROMPT-lane-backup.md new file mode 100644 index 0000000..db118a6 --- /dev/null +++ b/docs/PROMPT-lane-backup.md @@ -0,0 +1,57 @@ +# Kickoff-Prompt — Lane Backup/Restore/DSGVO (certvia) + +> Diesem Prompt einem Entwickler/Claude-Code-Agenten geben. Bootstrapt in certvia + diese Lane. + +```text +Du übernimmst die Lane „Datensicherung, Wiederherstellung & DSGVO" am Produkt „certvia" +(ISMS-Tool, Multi-Tenant Next.js-16 / Prisma-7 / Postgres+RLS / Auth.js-v5). Repo: +~/Projects/ISMS-Tool, Integrationsbranch `dev`. + +WICHTIG: certvia ist strikt getrennt von jedem anderen Produkt (insb. „visitvia"). Nichts vermischen. + +BRANCH/CHECKOUT: + Arbeits-Branch: `lane-backup` (KEIN `feature/`-Prefix — auf origin blockiert der Branch + `feature` diesen Namespace). Aus `dev` erstellen: git fetch origin && git checkout dev && + git checkout -b lane-backup. + Remotes: origin = https://git.certvia.de/msolarczek/certvia.git · local-gitea (intern). + +1) PFLICHTLEKTÜRE (erst lesen, nicht sofort coden): + - docs/HANDOVER-DEV.md, docs/SPEC.md, docs/STAND-dev-branch.md + - docs/KONZEPT-backup-restore.md ← dein Fahrplan (Schicht A/B, Portal, DSGVO, §9 Verschlüsselung) + - docs/KONZEPT-haertung.md §3 ← operativer Bezug „verschlüsselte Backups" + +2) AUFTRAG (Phasen aus dem Konzept §11): + (1) Schicht A: pgBackRest/wal-g + PITR, client-seitig AES-256 (§9) — Ops-nah, sofort möglich. + (2) Tenant-scoped Export/Restore-Engine über TENANT_MODELS (FK-Reihenfolge), REPEATABLE READ. + (3) Betreiber-Portal-Restore (Worker-Job, Kontrollen §4/§10). + (4) DSGVO-Export (per-Mandant + per-Person). + (5) DSGVO-Löschung (Anonymisieren vs. Hard-Delete + Löschnachweis + Tombstone-on-Restore). + +3) VERBINDLICHE REGELN: + - Engine läuft über den Owner-`prisma`-Client (BYPASSRLS), NIE den RLS-Client. + - Jede Operation `tenant_id`-gescopt (Export SELECT, Restore DELETE+INSERT, Löschung) → + beweisbar keine Fremdmandanten berührt. cuid-PKs: Reinsert kollisionsfrei. + - `Identity` ist GLOBAL: Tenant-Restore holt Mitgliedschaften (`User`), NICHT den globalen + Credential-Store (der liegt in Schicht A). Fehlende Identity beim Reinsert sauber behandeln. + - Verschlüsselung = §9-Primitiv: client-seitig AES-256, Keys pro Umgebung. Backup-Artefakte + enthalten KEINE Umgebungs-Secrets (Pepper/MFA_ENC_KEY) → Restore-Kohärenz dokumentieren. + - MinIO-Dateien (Prefix je Mandant) gehören zu Export/Restore/Löschung dazu. + - Destruktive Portal-Aktionen: requirePlatformFullAdmin + MFA-Step-up + getippte Bestätigung + + Mandant-Sperre + Pre-Restore-Snapshot + Audit. + +4) ARBEITSWEISE: + - Gate vor JEDEM Merge: npx tsc --noEmit · npm run lint · npm run build · ALLE scripts/test-*.ts. + Jede Story bringt ihren Test mit (Isolation: Restore/Export/Löschung berührt nur den Zielmandanten). + - DevOps: lane-backup → git merge --no-ff nach dev → Gate grün → Push auf BEIDE Remotes → + docs/STAND-dev-branch.md pflegen. + +5) KOORDINATION: + - §9-Verschlüsselung ist gemeinsam mit Lane Härtung: Mechanismus/Keys sind entschieden + (client-seitig AES-256, Keys pro Umgebung) — nur EINMAL abstimmen, dann unabhängig. + - prisma migrate reset gegen Test/Coolify braucht Nutzer-Zustimmung (Prisma-Guard). + +6) NICHT TUN: keine Änderung am Auth-/RLS-Kern; TENANT_MODELS bleibt Quelle der tenant-Tabellen. + +Erste Schritte: (a) Pflichtlektüre + 10-Zeilen-Zusammenfassung/Fragen, (b) FK-Reihenfolge aus +TENANT_MODELS ableiten + Engine-PR-Plan skizzieren, (c) nach Freigabe umsetzen. Warte nach (a)/(b). +``` diff --git a/docs/PROMPT-lane-framework-assessment.md b/docs/PROMPT-lane-framework-assessment.md new file mode 100644 index 0000000..af67225 --- /dev/null +++ b/docs/PROMPT-lane-framework-assessment.md @@ -0,0 +1,120 @@ +# Kickoff-Prompt — B1: Assessment und Readiness für zwei Frameworks + +Du baust die **Bewertungs- und Readiness-Schicht** für ISO 27001 neben TISAX. Alles andere steht bereits: Der Dokumentensatz trägt beide Normen, `mapping-iso.json` liefert 120 ISO-Anforderungen, die Framework-Dimension im Datenmodell ist gebaut (AP1–AP5), ein ISO-Mandant hat SoA, Kennzahlen, Managementbewertung und Korrekturmaßnahmen. + +**Was fehlt:** `maturity.ts`, `scope-filter.ts`, `assessment-level.ts` und `readiness.ts` kennen kein Framework und rechnen durchgängig VDA ISA — AL2/AL3, Prüfziele, Reifegrad 0–3, MUSS/SOLL. Der belegte Bruch: `src/server/soa-context.ts:151` und `src/server/export-context.ts:49` lesen `controlAssessment`; **keine einzige Stelle liest `soaEntry`**. Das SoA-Modul ist von der Auswertung abgekoppelt. + +**Pflichtlektüre vor der ersten Zeile Code:** `docs/FEINDESIGN-framework-assessment.md` — vollständig, insbesondere §1 (Leitentscheidung) und §7a (Priorisierung). Hintergrund: `docs/FRAMEWORK-MAPPING-ISO27001.md`, `docs/UEBERGABE-framework-iso27001.md`. + +## Repo & Branch +- **origin:** `git.certvia.de/msolarczek/certvia`; zweiter Remote `local-gitea`. +- **Basis ist `feature/iso27001-framework-mapping`**, nicht `dev`. +- Arbeite auf `feature/framework-assessment`, PR gegen den Basis-Branch. + +## Kundenlage — sie bestimmt, was jetzt gebaut wird + +Die Mehrzahl der Mandanten führt **TISAX**, **ein** Mandant **ISO**, **keiner beide**. + +Daraus folgt: **Das Regressionsrisiko dominiert dieses Paket.** Der gefährlichste Teil ist nicht die ISO-Logik — die ist schlank — sondern die verhaltensgleiche Extraktion der bestehenden TISAX-Logik. Sie betrifft jeden Bestandsmandanten. Schritt 1 ist deshalb keine Kür. + +**Zurückgestellt** (betrifft ausschließlich den Doppel-Mandanten, den es heute nicht gibt): +- Vorbelegung über `ISO_TO_ISA` (Übernahmevorschlag zwischen den Frameworks) +- Reiter-UI in `/soa` und `/audit-readiness` — bei einem aktiven Framework wird direkt angezeigt + +**Nicht zurückstellen:** die **Strategie-Schnittstelle** und den **Framework-Parameter** in `buildAssessment`. Beides kostet jetzt fast nichts und ist später teuer, weil sonst sieben Aufrufstellen erneut angefasst werden. Die Architektur bleibt zweigleisig, die Oberfläche zeigt vorerst ein Gleis. + +## Die eine Leitentscheidung + +**Die Belegbasis liegt unterhalb der Framework-Strategie.** Ob R08 freigegeben ist, ist eine Tatsache über die Organisation, keine Frage der Norm. `ControlEvidence` (`src/lib/maturity.ts:54`) wird geteilt; nur Scope, Zielwert, Bewertung und Vokabular sind framework-eigen. + +``` +Schicht 3 Sichten /soa · /audit-readiness · Exporte → je Framework (Reiter später) +Schicht 2 Strategie Scope · Zielwert · Bewertung → je Framework +Schicht 1 Belegbasis loadEvidenceResolver → ControlEvidence → GETEILT +Schicht 0 Fachdaten PolicyDocument · Evidence · Asset … → GETEILT +``` + +**Review-Kriterium, hart:** `loadEvidenceResolver` darf `FrameworkKey` nicht kennen. Sobald die Belegauflösung anfängt, das Framework zu fragen, ist der Schnitt gerissen und wir bekommen zwei Bewertungen derselben Realität, die auseinanderlaufen. + +## Nicht anfassen + +- **`seed/isms-vorlagenpaket-v2/**` und `-en/**`** — generiert. Änderungen nur über `_iso_crosswalk.json` / `_iso_sections.json` / `_iso_texts_en.json` + `python3 _generate_iso.py [--lang en]`. +- **Die VDA-ISA-Fachlogik inhaltlich** — `suggestMaturity`, `targetMaturity`, `openPoints`, `activeRequirements` werden **verschoben, nicht verändert**. +- **`readiness.ts` und `gap-consolidation.ts`** — numerisch standard-agnostisch, werden von beiden Strategien gefüttert. + +## Arbeitsschritte + +### 1 — Snapshot der heutigen TISAX-Ausgabe *(zuerst, vor jeder Änderung)* +`buildControlRows` für den Demo-Mandanten festhalten: Reifegradvorschlag, Zielwert, Belegstatus und offene Punkte je Control, als JSON im Repo. Ablage als `scripts/test-framework-assessment.ts` in der Hausform der übrigen `test-*.ts`. +**DoD:** Test läuft grün gegen den unveränderten Stand und ist als Merge-Gate gesetzt. + +### 2 — `ControlSpec` einführen +`C5ControlSpec` (`src/lib/maturity.ts:16`) auf ein neutrales `ControlSpec` reduzieren (`control`, `title`, `policy[]`, `verfahren[]`, `needsAsset`, `needsRisk`); `C5ControlSpec` erweitert es um `target`. `loadEvidenceResolver` (`src/server/soa-context.ts:50`) nimmt künftig `ControlSpec`. +**DoD:** Snapshot unverändert grün, `tsc` sauber. + +### 3 — ISO-Specs generieren +`_generate_iso.py` erzeugt zusätzlich `src/lib/control-specs-iso.ts` — analog zu `control-titles-iso.ts` und `iso-isa-crosswalk.ts`. Quelle ist `mapping-iso.json` (`policy` und `verfahren` stehen dort je Anforderung); `needsAsset`/`needsRisk` über `ISO_TO_ISA` vom ISA-Spec erben, für die 33 ISO-eigenen Abschnitte explizit setzen — sinnvoll nur bei A.5.9 (`needsAsset`) sowie 6.1.2/6.1.3/8.2/8.3 (`needsRisk`). +**DoD:** Generator idempotent, `_verify_iso.py` DE und EN grün, keine handgepflegte Zweitliste. + +### 4 — `FrameworkStrategy` + `TisaxStrategy` *(reine Extraktion)* +Interface nach §3 des Feindesigns. `TisaxStrategy` verdrahtet die vorhandenen Funktionen um: `loadScopeInput` + `controlsInScope` → `controlsInScope`, `suggestMaturity` + `targetMaturity` → `evaluate`, `openPoints` → `gaps`, `computeReadiness` → `summarise`. +**DoD:** Snapshot bitgenau grün. Jede Abweichung ist eine Regression, kein „ist besser geworden". + +### 5 — `IsoStrategy` +| Aspekt | Regel | +|---|---| +| Scope | `SoaEntry.applicable = true`; Klauseln 4–10 immer im Scope | +| Zielwert | `implementationStatus = "umgesetzt"`, keine Stufung | +| Vorschlag | Richtlinie *und* Verfahren `validiert` + geforderte Verknüpfungen → `umgesetzt`; teilweise → `teilweise`; sonst `geplant` | +| Bestätigung | `SoaEntry.implementationStatus`; der Vorschlag überschreibt ihn nie | +| Lücken | fehlende Begründung, fehlender Nachweis, Status ≠ „umgesetzt" bei anwendbarem Control | + +**DoD:** ISO-Mandant bekommt eine Bewertung über alle anwendbaren Controls; leere SoA meldet „Anwendbarkeit noch nicht erklärt" statt 0 %. + +### 6 — `buildAssessment(db, tenantId, framework)` +Ersetzt `buildControlRows` (`src/server/soa-context.ts:146`) und delegiert an die Strategie. Sieben Dateien rufen es direkt; insgesamt hängen 13 an der Assessment-Logik. +**DoD:** Alle Aufrufstellen umgestellt, Snapshot grün, `tsc`/`lint`/`build` grün. + +### 7 — ISO-Readiness-Bänder und Beschriftung +`REIFEGRAD_BANDS` (`src/lib/readiness.ts:16`) ist TISAX-Sprache („Assessment-reif", „AL-Ziel"). ISO bekommt eigene Bänder auf Basis des Umsetzungsgrads: < 50 % Aufbau · 50–79 % In Umsetzung · 80–99 % Zertifizierungsnah · 100 % Zertifizierungsreif. +**DoD:** In der ISO-Sicht erscheint kein AL-, Prüfziel- oder Reifegradbegriff. Ein ISO-Bericht argumentiert mit „umgesetzt, hier ist der Beleg", nicht mit „Reifegrad 2,4". + +### 8 — ISO-Exporte +SoA-Export und Annex-A-Gap-Report. Der VDA-ISA-Export bleibt TISAX-only und unverändert. +**DoD:** Der ISO-Mandant kann die Eingaben für seine Managementbewertung aus dem Tool ziehen. + +**Zusatznutzen, bitte mitnehmen:** Die 33 ISO-Anforderungen ohne ISA-Gegenstück als eigene Liste ausweisbar machen. Das ist genau die Delta-Arbeit, die ISO gegenüber TISAX zusätzlich verlangt — die erste Frage jedes TISAX-Kunden, der über ISO nachdenkt. + +## Validierungs-Gate vor jedem PR + +```bash +npx tsc --noEmit && npm run lint && npm run build +npx tsx scripts/test-framework-assessment.ts # Snapshot TISAX → 0 Abweichungen +npx tsx scripts/test-framework-dryrun.ts # Paket + Import → alle Prüfungen bestanden +cd seed/isms-vorlagenpaket-v2 +python3 _generate_iso.py && python3 _generate_iso.py --lang en # beide idempotent +python3 _verify.py && python3 _verify_iso.py && python3 _verify_iso.py --lang en +python3 _render_diff.py HEAD # TISAX-Renderdiff → 0 Abweichungen +``` + +Weitere Konventionen: Migrationsflow Prisma 7 mit manuell angehängtem RLS-DO-Block (`docs/HANDOVER-DEV.md:100`); neue mandantengebundene Modelle in `TENANT_MODELS` (`src/server/db.ts:81`) **und** RLS-Policy in der Migration; jede neue Datei unter `src/server/actions/` in `scripts/check-module-guards.ts` eintragen, sonst schlägt der Build fehl. + +## Definition of Done (gesamt) + +| Prüfung | Erwartung | +|---|---| +| Snapshot TISAX | 0 Abweichungen zur Ausgabe vor dem Umbau | +| Bestandsmandant (TISAX) | Verhalten und Beschriftung unverändert | +| ISO-Mandant | Readiness und SoA rechnen; kein TISAX-Vokabular in der Oberfläche | +| Architektur | Strategie-Schnittstelle und Framework-Parameter vorhanden, auch wenn die UI nur ein Gleis zeigt | +| Belegbasis | `loadEvidenceResolver` kennt `FrameworkKey` nicht | +| Kennzahlen | je Framework eine eigene, **keine** gemischte Gesamtzahl | +| Gate | alle Prüfungen oben grün | + +## Aufwand + +4–6 PT im vorgezogenen Umfang. Schritte 1–4 hängen aneinander und sind Pflicht; 5–8 sind danach teilbar. Schwerpunkt liegt auf Schritt 4, nicht auf der ISO-Logik. + +## Nicht dein Scope + +Vorbelegung zwischen den Frameworks und die Reiter-UI (siehe Kundenlage). Ebenso Paket- und Freigabearbeit: `REVIEW_CYCLE`-Split an 32 Bestandsstellen, ISB-Freigabe der 19 ISO-Abschnittstexte, Review des Crosswalks. diff --git a/docs/PROMPT-lane-framework-iso27001.md b/docs/PROMPT-lane-framework-iso27001.md new file mode 100644 index 0000000..989ec8e --- /dev/null +++ b/docs/PROMPT-lane-framework-iso27001.md @@ -0,0 +1,151 @@ +# Kickoff-Prompt — Framework-Dimension: ISO 27001 neben TISAX + +Du übernimmst den **Anwendungsumbau** für die Mehr-Framework-Fähigkeit. Die **Inhaltsseite ist fertig**: `seed/isms-vorlagenpaket-v2` trägt seit Branch `feature/iso27001-framework-mapping` **zwei Framework-Mappings auf einem Dokumentensatz** — `mapping.json` (VDA ISA, 321 Anforderungen) und `mapping-iso.json` (ISO/IEC 27001:2022, 120 Anforderungen). Die Anwendung kennt das zweite Mapping nicht: `parsePackageFiles` liest `mapping.json` fest verdrahtet. + +**Pflichtlektüre vor der ersten Zeile Code:** `docs/UEBERGABE-framework-iso27001.md` — insbesondere **§1 „Die vier Fallen"**. Hintergrund und Begründung der Entscheidung: `docs/FRAMEWORK-MAPPING-ISO27001.md`. Gesamtarchitektur: `docs/KONZEPT-framework-iso27001.md` (D4 und Lane 2 sind dort per Nachtrag korrigiert). + +## Repo & Branch +- **origin:** `git.certvia.de/msolarczek/certvia`; zweiter Remote `local-gitea`. +- **Basis ist `feature/iso27001-framework-mapping`**, nicht `dev` — dort liegt die Vorarbeit (Commits `492d315`, `bbde804`, `7769908`, `b28d0f0`). +- AP1 auf `feature/framework-core`, PR gegen den Basis-Branch. AP2–AP5 danach je eigener Branch, parallelisierbar. + +## Nicht anfassen +- **`seed/isms-vorlagenpaket-v2/**`** — generiert. Inhaltliche Änderungen laufen ausschließlich über `_iso_crosswalk.json` / `_iso_sections.json` + `python3 _generate_iso.py`, nie direkt in den Markdown-Dateien (der Generator überschreibt sentinel-begrenzte Blöcke). +- **Die TISAX-Logik verhaltensgleich lassen:** `src/lib/maturity.ts`, `src/lib/scope-filter.ts`, `src/server/assessment-level.ts`, `src/lib/control-titles.ts`, `src/lib/export/vda-isa*.ts`. Wenn du sie hinter eine `FrameworkStrategy` ziehst, muss das Verhalten identisch bleiben. + +## Vier Invarianten — hier geht es sonst schief + +1. **`reconcilePackage` archiviert fremde Anforderungen.** `prisma/import-policies.ts:368-371` setzt `archivedAt` auf jede `PolicyRequirement`, deren `reqId` nicht im importierten Paket steht. Ein ISO-Import in einen TISAX-Mandanten legt damit **alle 321 VDA-ISA-Anforderungen still** — und umgekehrt. Lösung: `PolicyRequirement.framework` ergänzen (Backfill `TISAX`) und den Archivierungslauf auf `where: { tenantId, framework }` einschränken. Für Dokumente, Variablen, Baseline und Nachweisregister gilt das **nicht** — die sind geteilt und identisch, sie dürfen genau einmal je Mandant abgeglichen werden. +2. **Zwei Unique-Constraints brechen.** `PolicyTemplateVersion.version @unique` (`prisma/schema.prisma:1639`) → `@@unique([framework, version])`, sonst kollidieren ISO 2.1 und TISAX 2.1. `PolicyPackageState.tenantId @unique` (`:1614`) → `@@unique([tenantId, framework])`, sonst merkt sich ein Mandant nur eine Paketversion. +3. **TISAX darf sich nicht verändern.** Messlatte ist `python3 seed/isms-vorlagenpaket-v2/_render_diff.py HEAD` → 0 Abweichungen. +4. **Den Fail-Safe in `src/lib/policy-render.ts` nicht entfernen.** `buildContext` belegt fehlende Framework-Flags vor (`FLAG_FW_TISAX = true`, `FLAG_FW_ISO27001 = false`), damit Bestandsmandanten vor dem Paket-Re-Import keine leeren Anforderungsblöcke sehen. + +## AP1 — Framework-Dimension *(Fundament, blockiert alles)* + +**Schema, additiv:** +```prisma +enum Framework { ISO_27001 TISAX } + +model TenantFramework { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + framework Framework + isPrimary Boolean @default(false) @map("is_primary") + config Json? // z. B. { tisaxLevel: "AL3" } bzw. { certScope } + createdAt DateTime @default(now()) @map("created_at") + @@unique([tenantId, framework]) + @@index([tenantId]) + @@map("tenant_frameworks") +} +``` +Dazu `PolicyRequirement.framework`, `PolicyTemplateVersion.framework`, `PolicyPackageState.framework`. Backfill aller Bestandsdaten auf `TISAX`. `TenantFramework` gehört in **`TENANT_MODELS`** (`src/server/db.ts:81`) und braucht eine **RLS-Policy in der Migration**. + +**Code:** +| Datei | Änderung | +|---|---| +| `prisma/import-policies.ts` | `parsePackageFiles(seedDir, mappingFile = "mapping.json")`; Requirements framework-scoped reconcilen | +| `prisma/template-store.ts:147` | `resolvePackageForTenant(prisma, tenantId, seedDir, framework)`; `loadPublishedPackage(prisma, locale, framework)`; `getAvailableVersion` ebenso | +| `scripts/sync-policy-templates.ts:23` | über **Frameworks × Sprachen** iterieren | + +Die vier Aufrufer bekommen den Parameter durchgereicht: `src/server/provision.ts:139`, `src/server/actions/policy-package.ts:28`, `src/server/actions/admin.ts`, `src/app/(app)/policies/updates/page.tsx:44`. **Das Seed-Verzeichnis bleibt für beide Frameworks dasselbe** — die fünf `SEED_DIR`-Konstanten ändern sich nicht, nur der Mapping-Dateiname. + +**DoD:** Bestandsmandanten laufen unverändert als TISAX; ein Mandant lässt sich mit `["ISO_27001"]`, `["TISAX"]` oder beiden provisionieren; bei Doppel-Framework koexistieren 321 + 120 Anforderungen und **keine** ist fälschlich archiviert. + +## AP2 — Provisionierung und Flags *(klein, direkt nach AP1)* + +`ProvisionOpts` (`src/server/provision.ts:37`) um `frameworks: Framework[]`. `provisionTenant` schreibt die `TenantFramework`-Zeilen, importiert je Framework das passende Mapping und setzt die Sichtbarkeits-Flags als `PolicyVariable`: nur TISAX → `true/false`, nur ISO → `false/true`, beides → `true/true`. + +**Reihenfolge beachten:** `reconcilePackage` erhält nutzergepflegte Variablenwerte und überschreibt sie nicht — die Flags also **nach** dem Import setzen, sonst bleibt der Schema-Default stehen und ein ISO-Mandant sieht die VDA-ISA-Sicht. `tisaxLevel` bleibt auf `TenantSettings`, ist aber TISAX-scoped; bei einem reinen ISO-Mandanten keine AL-Flags setzen. + +**DoD:** Frisch provisionierter ISO-Mandant öffnet `/policies` und sieht je Abschnitt `*Anforderungsbezug:* ISO/IEC 27001 …` plus die 19 ISO-only-Abschnitte; keine VDA-ISA-Anforderungen. + +## AP3 — SoA-Modul *(das fehlende ISO-Kernartefakt)* + +Der Modul-Key `soa` (`src/lib/modules.ts:19`) zeigt auf `/soa`, **die Route existiert nicht**; die heutige Logik liegt als Wizard-Schritt in `src/server/actions/soa.ts` und ist ein VDA-ISA-Reifegrad-Assessment (0–3), nicht die ISO-Anwendbarkeitserklärung. + +```prisma +model SoaEntry { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + framework Framework + control String // "A.5.15" + applicable Boolean @default(true) + justification String // Begründung Einbeziehung ODER Ausschluss + source String? // Risiko-ID / gesetzliche / vertragliche Anforderung + implementationStatus String @default("geplant") // umgesetzt | teilweise | geplant + ownerId String? @map("owner_id") + policyCode String? @map("policy_code") + evidenceId String? @map("evidence_id") + @@unique([tenantId, framework, control]) + @@index([tenantId]) + @@map("soa_entries") +} +``` + +`applicable`, `justification`, `implementationStatus` und die Ausschlussbegründung sind **normative Pflichtangaben** (ISO/IEC 27001:2022, 6.1.3 d) — ohne sie ist die SoA im Zertifizierungsaudit angreifbar. Vorbefüllung aus `mapping-iso.json` (93 Controls); das Feld `condition` steuert die Default-Anwendbarkeit. Fachliche Vorlage für Aufbau und Spalten: `seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md`. + +**DoD:** SoA vollständig pflegbar und als PDF/XLSX exportierbar; ein Control ohne Begründung wird als unvollständig markiert. + +## AP4 — Kennzahlen, Managementbewertung, Korrekturmaßnahmen + +| Klausel | Modell | Inhalt | +|---|---|---| +| 9.1 | `Kpi` / `KpiValue` | Kennzahl, Datenquelle, Zielwert, Turnus, Verantwortlicher, Messwerte je Periode | +| 9.3 | `ManagementReview` | Datum, Eingaben nach 9.3.2, Ergebnisse nach 9.3.3, Beschlüsse mit Verantwortlichem und Termin | +| 10.2 | `Nonconformity` + `CorrectiveAction` | Herkunft, Sofortkorrektur, Ursachenanalyse, Maßnahme, Wirksamkeitsbewertung | + +Aufsetzen auf Vorhandenes: `Task.recurrence` (RRULE), `Task.remindAt`, `Task.effectiveUntil` (Wirksamkeitsintervall, gekoppelt an `Evidence.validUntil`), `TaskParticipant` (RACI), `AuditLog`. Datenquellen für Kennzahlen liegen bereits im Tool: Aufgabenfristen und Überfälligkeit, Incident-SLA und Meldefristen (`src/lib/incident-deadlines.ts`), Reifegrade je Control, Maßnahmenstatus. Die Feldinhalte stehen fachlich in R03 der Bibliothek (`ISO-MS-MESSUNG`, `ISO-MS-MGMTREVIEW`, `ISO-MS-CAPA`). + +**DoD:** Kennzahlenblatt mit Zielwerten über zwei Perioden auswertbar; Management-Review entlang der 9.3.2-Agenda protokollierbar; ein Maßnahmenfall inklusive dokumentierter Wirksamkeitsprüfung abschließbar. + +## AP5 — Dokumentenlenkung *(klein, hohe Auditwirkung)* + +- `PolicyDocument.reviewCycle` + `nextReviewAt` — heute führt nur `ManagedRegister` einen `reviewCycle`; A.5.1 verlangt die Überprüfung „in geplanten Abständen". +- `PolicyAcknowledgement { tenantId, policyDocumentId, version, userId, acknowledgedAt }` — Lesebestätigung, in `SPEC.md` §4.6 vorgesehen und bis heute nicht gebaut. Zugleich der einfachste Nachweis für Klausel 7.3 und Control A.6.3. +- Änderungshistorie je Dokumentversion — aus `AuditLog` (Vorher/Nachher) ableitbar oder eigene Tabelle. + +**DoD:** Übersicht „Prüfung fällig"; Auswertung der Lesebestätigungen je Richtlinienversion; Dokumenthistorie über mindestens zwei Versionen sichtbar. + +## Validierungs-Gate vor jedem PR + +```bash +npx tsc --noEmit && npm run lint && npm run build +cd seed/isms-vorlagenpaket-v2 +python3 _verify.py # TISAX-Sicht → OK +python3 _verify_iso.py # ISO-Sicht → OK (0 Befunde) +python3 _render_diff.py HEAD # TISAX-Regression → 0 Abweichungen +``` + +Zusätzlich beachten: +- **Migrationsflow Prisma 7** (`docs/HANDOVER-DEV.md:100`): `migrate diff --from-config-datasource … --to-schema … --script`, danach den **RLS-DO-Block manuell** an die `migration.sql` anhängen, dann `migrate deploy`. +- **`scripts/check-module-guards.ts`** läuft als `prebuild`-Gate: jede neue Datei unter `src/server/actions/` dort eintragen (Modul-Key oder `EXEMPT`), sonst schlägt der Build fehl. +- Bei paralleler Lane-Entwicklung teilen sich die Worktrees dieselbe lokale Postgres-DB: beim Erzeugen einer Migration nur die **eigenen** DDL-Blöcke übernehmen, Fremd-Drops von Hand entfernen. + +## Definition of Done (gesamt) + +| Prüfung | Erwartung | +|---|---| +| Bestandsmandant (TISAX) nach Deploy | Readiness und Exporte identisch zum Snapshot vor dem Umbau | +| Import ISO in Mandant mit TISAX | 120 neue Anforderungen, **0 archivierte** ISA-Anforderungen | +| Import ISO, Umsetzungstexte | 120 von 120 gefüllt | +| Dokumente bei Doppel-Framework | 39 Dokumente, **nicht** doppelt | +| Parallelbetrieb im Dokument | beide Anforderungssichten unter einem gemeinsamen Umsetzungstext | +| Gate | tsc, lint, build, beide `_verify*`, `_render_diff` grün | + +`parsePackageFiles` ist reine Dateiarbeit und ohne Datenbank testbar; für den Mandanten-Import gibt es `reconcilePackage(..., { dryRun: true })` — Änderungsreport ohne Schreibzugriff, geeignet als Freigabebedingung. + +## Reihenfolge und Aufwand + +``` +AP1 Framework-Dimension 4–6 PT ← blockiert alles + ├─ AP2 Provisionierung 1–2 PT + ├─ AP3 SoA-Modul 5–8 PT + ├─ AP4 Managementkl. 5–8 PT + └─ AP5 Dok.-Lenkung 2–3 PT +``` + +AP3–AP5 sind nach AP1 parallelisierbar. **Feature-Flag:** ISO bleibt laut Entscheidung D7 hinter einem Plattform-Schalter, bis AP3 abgenommen ist. + +## Nicht dein Scope + +Diese Punkte gehören dem ISB bzw. der Redaktion: Nachweisregister um Zeilen für Kennzahlenblatt, Management-Review-Protokoll und Maßnahmenregister ergänzen; VA-15 trennen und ein Verfahren für Korrekturmaßnahmen ergänzen (**Nummer ab VA-21**, VA-20 ist belegt); `REVIEW_CYCLE` an den 33 Bestandsstellen auf die getrennten Zyklus-Variablen umstellen; ISB-Freigabe der 19 neuen Abschnittstexte. diff --git a/docs/PROMPT-lane-garage-abnahme.md b/docs/PROMPT-lane-garage-abnahme.md new file mode 100644 index 0000000..338beed --- /dev/null +++ b/docs/PROMPT-lane-garage-abnahme.md @@ -0,0 +1,42 @@ +# Kickoff-Prompt — Lane D: Test, Cutover & Abnahme + +Du übernimmst **Lane D** (Integration/Abnahme) der Umstellung **MinIO → Garage**. Lies `docs/KONZEPT-garage-migration.md` (v. a. §7 Runbook, §8 Rollback, §9 Abnahmekriterien). **Randbedingung:** nur Test-Instanzen, keine Datenmigration — Neu-Deploy. + +## Repo & Branch +- **origin:** `git.certvia.de/msolarczek/certvia` — Basis-Branch **`dev`**. +- Zweiter Remote (interner Coolify-Test): `local-gitea` = `gitea.192.168.1.155.sslip.io/msolarczek/ISMS-Tool`. Push auf `dev` löst den Test-Deploy aus. +- Deploy-Ziel: interne Coolify-Instanz, `certvia.192.168.1.155.sslip.io`. + +## Ziel +Die integrierten Ergebnisse aus Lane A–C auf der Test-Instanz **per Neu-Deploy** in Betrieb nehmen und **formal abnehmen** — plus abgenommenes Runbook (auch für spätere Prod). + +## Aufgaben +1. **Cutover (Runbook §7)** an der Test-Instanz durchspielen: + - Im Compose `minio` → `garage` + `garage-provision`; Volumes `garage_meta`/`garage_data`. + - Coolify-Env: `S3_ENDPOINT=http://garage:3900`, `S3_REGION=us-east-1`, `GARAGE_RPC_SECRET`, `GARAGE_ADMIN_TOKEN` (literal!), `S3_ACCESS_KEY/S3_SECRET_KEY` = provisionierter Garage-Key. + - Deploy; Garage „ready", `garage-provision` legt Bucket/Key/Rechte an. + - Optional DB-Reset (wie in bisherigen Deploys), falls alte Objekt-Referenzen stören. +2. **End-to-End-Abnahme (§9)** — alle grün: + - Upload (Richtlinie/Nachweis) → Objekt in Garage, `/uploads/…`-Präfix korrekt. + - Download (`/files/[...key]`) inkl. korrektem Dateinamen/Content-Type. + - Backup-Export `.cvb` (CVB1-Header), Persistenz + Download. + - DSGVO-ZIP erzeugt + lesbar. + - Restore → Datenintegrität + **Mandanten-Isolation**. + - Backup-Historie: List + Aufräumen (Delete-Prefix). + - Negativfall: fehlender Bucket → sprechender Konfigfehler (kein stiller CreateBucket). + - `scripts/test-backup-*.ts` + `scripts/test-garage-storage.ts` grün gegen die Instanz. +3. **Runbook & Rollback** in `docs/DEPLOY-COOLIFY.md` finalisieren (Schritt-für-Schritt, inkl. „`garage_meta` sichern"). +4. **`minio`-Service + Volumes** erst nach erfolgreicher Abnahme entfernen (bis dahin Rollback-Sicherheitsnetz). + +## Vorgaben +- **Keine echten Secrets in Chat/Repo/Logs** (`GARAGE_*`, S3-Key). In Coolify **literal** setzen (Interpolationsfalle). +- Bei „Container weg ohne Logs" die bekannte **Log-Capture-Technik** nutzen (Logs während des Deploys in Dateien mitschreiben; siehe Deployment-Erfahrungen). +- Gefundene Bugs an die jeweilige Lane (A/B/C) zurückspielen, nicht selbst quer patchen. + +## Definition of Done +- Test-Instanz läuft auf Garage, alle Abnahmekriterien (§9) abgehakt. +- Runbook + Rollback dokumentiert und einmal real durchgespielt. +- `minio` entfernt (oder bewusst als Netz belassen, dokumentiert). Freigabe für spätere Prod. + +## Abhängigkeiten +Integriert **Lane A + B + C**. PM koordiniert Reihenfolge (A→B, C parallel) und Go für die Abnahme. diff --git a/docs/PROMPT-lane-garage-code.md b/docs/PROMPT-lane-garage-code.md new file mode 100644 index 0000000..8eae5fa --- /dev/null +++ b/docs/PROMPT-lane-garage-code.md @@ -0,0 +1,36 @@ +# Kickoff-Prompt — Lane C: App-Code Garage-tauglich + +Du übernimmst **Lane C** der Umstellung **MinIO → Garage**. Lies `docs/KONZEPT-garage-migration.md` (v. a. §3 und §4 D3). **Kern:** Der S3-Code bleibt inhaltlich gleich (AWS SDK v3, `forcePathStyle`), aber die Selbstheilung `ensureBucket()` (HeadBucket→**CreateBucket**) muss weg — Garage unterstützt S3-`CreateBucket` nicht; Buckets werden von Lane B vorab provisioniert. + +## Repo & Branch +- **origin:** `git.certvia.de/msolarczek/certvia` — Basis-Branch **`dev`**. +- Zweiter Remote: `local-gitea` = `gitea.192.168.1.155.sslip.io/msolarczek/ISMS-Tool`. +- Arbeite auf `feature/garage-code` (aus `dev`), PR nach `dev`. **Unabhängig von Lane A/B** entwickelbar (gegen einen lokalen Garage-Container testen). + +## Scope (genau diese Dateien) +- `src/server/storage/adapter.ts` — `ensureBucket()` anpassen. +- `src/server/storage/backup-store.ts` — `ensureBucket()` anpassen. +- `.env.coolify.example` + `.env.example` — Kommentare MinIO → Garage, `S3_ENDPOINT`-Beispiel `http://garage:3900`, `forcePathStyle`-Begründung bleibt gültig. +- Tests unter `scripts/` (neuer Smoke-Test). +- **Nicht anfassen:** Compose/Infra (Lane A), Provisioning (Lane B), Fachlogik/UI. + +## Aufgaben +1. **`ensureBucket()` in beiden Stores** von „HeadBucket→CreateBucket" auf **nur prüfend** umstellen: + - `HeadBucketCommand` → wenn ok, weiter. + - Wenn Bucket fehlt/kein Zugriff → **klarer Konfigurationsfehler** werfen: „Bucket `` nicht provisioniert/kein Zugriff — Garage-Provisioning (Lane B) ausführen." **Kein** `CreateBucketCommand` mehr. + - `CreateBucketCommand`-Import entfernen, wenn ungenutzt (tsc/lint sauber halten). + - Beachte: `backup-store.ts` schluckt heute den Fehler still — das durch die neue, sprechende Variante ersetzen. +2. **Region/Endpoint-Doku** aktualisieren (Default `S3_REGION=us-east-1` bleibt, passend zu Garage-`s3_region`). +3. **Smoke-Test** (`scripts/test-garage-storage.ts` o. ä.): gegen einen lokalen Garage-Container Put→Get→(List/Delete beim Backup-Store) grün; plus Negativfall „Bucket fehlt → sprechender Fehler". + +## Vorgaben +- **API der Storage-Abstraktion unverändert** (`StorageAdapter`/`BackupStore`-Interfaces, Key-Schema, Local-/Stub-Fallback bleiben). +- Keine neuen Pflicht-Env; `S3_*`-Kontrakt bleibt. +- **Validierungs-Gate vor PR:** `npx tsc --noEmit`, Lint, `npm run build`, alle `scripts/test-*.ts` grün (inkl. neuem Test). Denk an die bekannte Falle: **nichts, was Secrets liest, auf Modulebene aufrufen** (Build-Kompatibilität). + +## Definition of Done +- Beide `ensureBucket()` prüfen nur noch, mit sprechendem Fehler bei fehlendem Bucket. +- Doku aktualisiert; Smoke-Test grün gegen lokale Garage; Gate grün. + +## Abhängigkeiten +Zur **Laufzeit** auf **Lane B** angewiesen (Bucket muss existieren), aber **Code + Tests unabhängig** entwickelbar (lokaler Garage-Container). diff --git a/docs/PROMPT-lane-garage-infra.md b/docs/PROMPT-lane-garage-infra.md new file mode 100644 index 0000000..41e13d8 --- /dev/null +++ b/docs/PROMPT-lane-garage-infra.md @@ -0,0 +1,35 @@ +# Kickoff-Prompt — Lane A: Garage Infra & Deployment + +Du übernimmst **Lane A** der Objektspeicher-Umstellung **MinIO → Garage**. Lies zuerst das Gesamtkonzept: `docs/KONZEPT-garage-migration.md` (v. a. §3 Reibungspunkt, §5 Zielarchitektur, §6 Lane A, §7 Runbook). **Randbedingung:** nur Test-Instanzen, keine Datenmigration — kompletter Neu-Deploy. + +## Repo & Branch +- **origin:** `git.certvia.de/msolarczek/certvia` — Basis-Branch **`dev`**. +- Zweiter Remote (interner Coolify-Test): `local-gitea` = `gitea.192.168.1.155.sslip.io/msolarczek/ISMS-Tool`. Ein Push auf `dev` löst den Test-Deploy aus. +- Arbeite auf `feature/garage-infra` (aus `dev`), PR nach `dev`. Nach Merge `dev` auf **beide** Remotes pushen. + +## Ziel +Garage als Compose-Service, der `minio` in `docker-compose.coolify.yml` ersetzt — lauffähig auf der Test-Instanz, Admin-API erreichbar, Single-Node-Layout „ready". + +## Scope (nur diese Dateien/Bereiche) +- `docker-compose.coolify.yml`: `minio`-Service durch `garage` ersetzen (nicht sofort löschen — auskommentiert/parallel lassen, bis Lane D abnimmt). +- `garage.toml` (neu, als Config-Mount oder über Env) + ggf. `docs/DEPLOY-COOLIFY.md` ergänzen. +- Keine App-Code-Änderung (das ist Lane C). + +## Vorgaben +- **Image pinnen** auf eine aktuelle stabile Garage-Version (`dxflrs/garage:vX.Y.Z`), nicht `latest`. +- **Ports:** 3900 = S3-API (von der App genutzt), 3903 = Admin-API (clusterintern, für Healthcheck/Provisioning), 3902 = Web optional. **Nichts nach außen (Traefik) freigeben** — genau wie MinIO bisher. +- **`garage.toml`:** `replication_factor = 1` (Single-Node), `metadata_dir`, `data_dir`, `rpc_secret` (aus `GARAGE_RPC_SECRET`), Block `[s3_api] s3_region = "us-east-1"`, `api_bind_addr = "[::]:3900"`, Block `[admin] api_bind_addr = "[::]:3903"`, `admin_token` (aus `GARAGE_ADMIN_TOKEN`). +- **Volumes:** `garage_meta → /var/lib/garage/meta` (KRITISCH), `garage_data → /var/lib/garage/data`. +- **Security analog Bestand:** `security_opt: no-new-privileges`, `cap_drop: ALL`, Resource-Limits, `restart: unless-stopped`. +- **Healthcheck** gegen Admin-API `/health` (3903). +- **Layout-Bootstrap** dokumentieren: nach erstem Start Node einer Zone mit Kapazität zuweisen (`garage layout assign …` → `garage layout apply`). Falls möglich, an Lane B (Provisioning-Job) delegieren — dann hier nur vorbereiten. +- **Secrets:** `GARAGE_RPC_SECRET` (32-byte hex) und `GARAGE_ADMIN_TOKEN` als Coolify-Env, **literal** setzen (nicht über `${…}` referenzieren — bekannte Coolify-Interpolationsfalle). **Keine echten Secrets ins Repo oder in Logs.** + +## Definition of Done +- Garage-Container startet in der Test-Instanz, Admin-`/health` grün, Layout „ready". +- `S3_ENDPOINT=http://garage:3900` intern erreichbar (kurzer `aws s3 ls`/curl-Nachweis). +- `garage_meta` als zu sicherndes Volume in `docs/DEPLOY-COOLIFY.md` vermerkt. +- Übergabepunkt an Lane B (Provisioning) klar dokumentiert (wie CLI/Admin-API erreichbar ist). + +## Abhängigkeiten +Lane B (Provisioning) baut direkt auf dir auf. Stimme das CLI-/Admin-API-Zugriffsmodell mit Lane B ab. diff --git a/docs/PROMPT-lane-garage-provision.md b/docs/PROMPT-lane-garage-provision.md new file mode 100644 index 0000000..1818a32 --- /dev/null +++ b/docs/PROMPT-lane-garage-provision.md @@ -0,0 +1,37 @@ +# Kickoff-Prompt — Lane B: Garage Provisioning (Bucket/Key/Rechte) + +Du übernimmst **Lane B** der Umstellung **MinIO → Garage**. Lies `docs/KONZEPT-garage-migration.md` (v. a. §3 „einziger Reibungspunkt", §4 D3, §6 Lane B). **Kern:** Garage legt Buckets/Keys **nicht** über S3-`CreateBucket` an, sondern über **Admin-API/CLI** — das automatisieren wir hier, idempotent. + +## Repo & Branch +- **origin:** `git.certvia.de/msolarczek/certvia` — Basis-Branch **`dev`**. +- Zweiter Remote: `local-gitea` = `gitea.192.168.1.155.sslip.io/msolarczek/ISMS-Tool` (Push auf `dev` = Test-Deploy). +- Arbeite auf `feature/garage-provision` (aus `dev`), PR nach `dev`. + +## Ziel +Ein **idempotenter Init-Job `garage-provision`** (Compose-Service, `restart: no`, analog `migrate`), der aus einer frisch gestarteten Garage reproduzierbar den betriebsbereiten Zustand herstellt. + +## Scope +- Neuer Compose-Service `garage-provision` in `docker-compose.coolify.yml` (mit Lane A abstimmen; `depends_on: garage`). +- Provisioning-Skript (`scripts/garage-provision.*` oder Shell im Job) — CLI **oder** Admin-API (HTTP). Entscheidung im Skript-Kommentar begründen. +- Doku in `docs/DEPLOY-COOLIFY.md`. + +## Aufgaben (alle idempotent — mehrfach ausführbar ohne Fehler) +1. **Layout** sicherstellen (falls Lane A das nicht schon macht): Node zuweisen + `layout apply`. +2. **Bucket(s)** anlegen: `isms-documents` (Uploads); Backup-Bucket nur, falls Backup-Store auf S3 statt `BACKUP_LOCAL_DIR` läuft. +3. **Access-Key** bereitstellen — **deterministisch**: bevorzugt vorhandenen Key **importieren** (`garage key import` mit den Werten aus `S3_ACCESS_KEY`/`S3_SECRET_KEY` der Coolify-Env), damit App-Env und Garage garantiert synchron sind. (Alternative: Key erzeugen und Ausgabe in Coolify-Secrets übernehmen — nur wenn Import nicht praktikabel; Trade-off dokumentieren.) +4. **Rechte** setzen: Key → Bucket read/write (owner nach Bedarf). +5. **Verifikation:** am Ende prüfen, dass Bucket existiert und der Key Schreib-/Leserecht hat; bei Fehlkonfiguration mit klarer Meldung + Exit ≠ 0 abbrechen. + +## Vorgaben +- **Idempotenz zwingend:** vor jedem `create` Existenz prüfen; „already exists" als Erfolg werten (der Job läuft bei JEDEM Deploy). +- **Kein Secret in Logs** (Key/Secret nicht ausgeben). `GARAGE_ADMIN_TOKEN` aus Env. +- Nicht crash-loopen bei fehlender Config: klare Fehlermeldung, definierter Exit (der Job ist `restart:no`, kein Dauerdienst). +- **Keine App-Code-Änderung** (Lane C). + +## Definition of Done +- Aus „leerer Garage" stellt ein einziger Job-Lauf Bucket + Key + Rechte her; zweiter Lauf ist ein sauberer No-Op. +- Danach greift `HeadBucket` der App erfolgreich (Übergabe an Lane C/D). +- Runbook-Schritt in `docs/DEPLOY-COOLIFY.md` dokumentiert. + +## Abhängigkeiten +Braucht **Lane A** (Garage-Service + Admin-Zugriff). Liefert die Vorbedingung für **Lane C** (`ensureBucket` prüft nur) und **Lane D** (Abnahme). diff --git a/docs/PROMPT-lane-haertung.md b/docs/PROMPT-lane-haertung.md new file mode 100644 index 0000000..3c3bf70 --- /dev/null +++ b/docs/PROMPT-lane-haertung.md @@ -0,0 +1,55 @@ +# Kickoff-Prompt — Lane Sicherheitshärtung (certvia) + +> Diesem Prompt einem Entwickler/Claude-Code-Agenten geben. Bootstrapt in certvia + diese Lane. + +```text +Du übernimmst die Lane „Sicherheitshärtung" am Produkt „certvia" (ISMS-Tool, Multi-Tenant +Next.js-16 / Prisma-7 / Postgres+RLS / Auth.js-v5). Repo: ~/Projects/ISMS-Tool, Branch `dev`. + +WICHTIG: certvia ist strikt getrennt von jedem anderen Produkt (insb. „visitvia"). Nichts vermischen. + +BRANCH/CHECKOUT: + Arbeits-Branch: `lane-haertung` (KEIN `feature/`-Prefix — origin-Namespace-Konflikt). + git fetch origin && git checkout dev && git checkout -b lane-haertung. + Remotes: origin = https://git.certvia.de/msolarczek/certvia.git · local-gitea (intern). + +1) PFLICHTLEKTÜRE: + - docs/HANDOVER-DEV.md, docs/SPEC.md, docs/STAND-dev-branch.md + - docs/KONZEPT-haertung.md ← dein Fahrplan + - docs/KONZEPT-backup-restore.md §9 ← das gemeinsame Verschlüsselungs-Primitiv + +2) AUFTRAG (Phasen aus dem Konzept §7): + (1) PEPPER (App) — JETZT, solange test/dev-DBs frisch/leer sind. + (2) Host-Encryption (LUKS/Volume) + verschlüsselte Backups (Ops, mit Backup-Lane). + (3) Secrets-Register formalisieren. + (4) DB-TLS (sslmode) + Vault/KMS = Phase 2. + +3) VERBINDLICHE REGELN: + - PEPPER: über Argon2-`secret` bei hash() UND jeder verify()-Stelle. Env `PASSWORD_PEPPER` + (32-Byte hex). Nach Option C ist der verify-Pfad zentral (Login gegen Identity) → wenn nötig + einen verifyPassword(hash,pw)-Wrapper einführen, damit Pepper EINE Stelle ist. + - ⚠ Pepper ist NICHT rotierbar ohne Passwort-Reset für alle (wie MFA_ENC_KEY) → bewusst + JETZT setzen, leere DBs nutzen. Restore-Kohärenz: Pepper ist Umgebungs-Secret, nicht im Artefakt. + - Argon2-PARAMETER sind ERLEDIGT (src/server/password.ts, ARGON2_OPTIONS) — nicht anfassen, + nur den `secret` ergänzen. + - Host-Encryption/Backup-Verschlüsselung sind OPS-Runbook (kein App-Code) → in + docs/DEPLOY-PROD-CONTABO.md als Go-Live-Punkte ergänzen; §9-Mechanismus (AES-256 client-seitig, + Keys pro Umgebung) verwenden. + - Secrets-Register: AUTH_SECRET · MFA_ENC_KEY · PASSWORD_PEPPER · pgBackRest-Key · age-Keypair; + je Umgebung getrennt, nie im Artefakt-Bucket, Offline-Kopie versiegelt. + +4) ARBEITSWEISE: + - Gate vor JEDEM Merge: tsc · lint · build · ALLE scripts/test-*.ts. Der Pepper braucht einen Test + (hash+verify mit gesetztem Pepper; verify schlägt fehl bei falschem/fehlendem Pepper). + - DevOps: lane-haertung → git merge --no-ff nach dev → Gate grün → Push auf BEIDE Remotes → + STAND pflegen. + +5) KOORDINATION: §9-Verschlüsselung gemeinsam mit Lane Backup (Mechanismus/Keys entschieden — einmal + abstimmen). Pepper-Rollout NUR auf Umgebungen mit leerer/frischer DB (sonst Passwort-Reset nötig). + +6) NICHT TUN: keine Auth-Logik-Änderung außer dem Pepper; keine Rotation eines gesetzten Peppers/ + MFA_ENC_KEY ohne expliziten Reset-Plan; Argon2-Parameter unverändert lassen. + +Erste Schritte: (a) Pflichtlektüre + Fragen, (b) Pepper-PR-Plan (Env, verify-Wrapper, Test) + +Bestätigung „Pepper jetzt setzen, DBs leer" einholen, (c) umsetzen. Warte nach (a)/(b). +``` diff --git a/docs/PROMPT-lane-ui-i18n.md b/docs/PROMPT-lane-ui-i18n.md new file mode 100644 index 0000000..0a3d035 --- /dev/null +++ b/docs/PROMPT-lane-ui-i18n.md @@ -0,0 +1,58 @@ +# Kickoff-Prompt — Lane Betreiber-Konsole-UX + i18n (certvia) + +> Diesem Prompt einem Entwickler/Claude-Code-Agenten geben. Bootstrapt in certvia + diese Lane. + +```text +Du übernimmst die Lane „Betreiber-Konsole-UX + vollständige i18n" am Produkt „certvia" (ISMS-Tool, +Multi-Tenant Next.js-16 / Prisma-7 / Postgres+RLS / Auth.js-v5). Repo: ~/Projects/ISMS-Tool, Branch `dev`. + +WICHTIG: certvia ist strikt getrennt von jedem anderen Produkt (insb. „visitvia"). Nichts vermischen. + +BRANCH/CHECKOUT: + Arbeits-Branch: `lane-ui-i18n` (KEIN `feature/`-Prefix — origin-Namespace-Konflikt). + git fetch origin && git checkout dev && git checkout -b lane-ui-i18n. + Remotes: origin = https://git.certvia.de/msolarczek/certvia.git · local-gitea (intern). + +1) PFLICHTLEKTÜRE: + - docs/HANDOVER-DEV.md, docs/SPEC.md, docs/STAND-dev-branch.md + - docs/KONZEPT-ui-i18n.md ← dein Fahrplan (Bugfix 1+2, Ergänzungen A/B) + +2) AUFTRAG: + BUGFIX 1 — Betreiber-Konsole (src/app/(platform)/admin/[id]/page.tsx): + - Module → Popup (searchParam `?modules=1`, ); Benutzer → Popup (`?users=1`). + Muster existiert bereits auf der Seite (?new/?edit/?audit) — analog kapseln. + - Hauptfenster stattdessen: Stammdaten (aus TenantSettings) + Hauptkontakt sichtbar. + Offene Kleinentscheidung: Hauptkontakt = neue Felder in TenantSettings vs. Ableitung aus + tenant-admin — mit PM klären. + BUGFIX 2 — Vollständige UI-Sprache + per-Mitarbeiter-Umschaltung: + - BEFUND: messages/en.json existiert (~95%), aber src/i18n/request.ts ist HART auf "de" + (Zeile 8). TenantSettings.locale steuert nur die Richtlinien-Import-Sprache, NICHT die UI. + - Neu: Identity.uiLocale (de|en, Default de) — persönliche Präferenz, folgt der Person. + - request.ts liest uiLocale der aktiven Session-Identity (Fallback de). + - Umschalter im Nutzer-Menü (Header/Profil) → Server-Action setUiLocale → speichern + reload. + - messages/en.json auf 100% prüfen/auffüllen; hartkodierte deutsche Strings in Komponenten + aufspüren und in den Katalog überführen. + ERGÄNZUNG A — Login: Organisationsfeld (`tenant`) aus src/app/login/page.tsx ENTFERNEN + (nach Option C überflüssig; Mandant kommt über /select-tenant). login-ticket-Signaturen entschlacken. + +3) VERBINDLICHE REGELN: + - UI-Sprache (Identity.uiLocale, Person) und Vorlagen-Import-Sprache (TenantSettings.locale, + Inhalt) sind ZWEI getrennte Achsen — nicht vermischen. + - Popups über das bestehende searchParam/-Muster, KEINE neue Modal-Infrastruktur. + - Stammdaten haben EINE Quelle (TenantSettings) — keine Doppelpflege einführen. + - RLS/Datenpfade unverändert; das ist eine reine UI-/Präferenz-Lane. + +4) ARBEITSWEISE: + - Gate vor JEDEM Merge: tsc · lint · build · ALLE scripts/test-*.ts. + - UI-Verifikation im Browser: Betreiber-Popups (Module/Benutzer), Sprachumschaltung DE↔EN + (Menü + Beschreibungen wechseln), Login ohne Organisationsfeld, /select-tenant unverändert. + - DevOps: lane-ui-i18n → git merge --no-ff nach dev → Gate grün → Push auf BEIDE Remotes → + STAND pflegen. + +5) NICHT TUN: keine Änderung am Auth-Kern/an /select-tenant-Logik; Identity.uiLocale nur als + Präferenzfeld ergänzen (keine Auth-Semantik). + +Erste Schritte: (a) Pflichtlektüre + Fragen (v.a. Hauptkontakt-Feld), (b) PR-Plan je Bugfix +(Migration Identity.uiLocale, request.ts, Menü-Switcher; Popup-Umbau admin/[id]), (c) umsetzen. +Warte nach (a)/(b). +``` diff --git a/docs/PROMPT-uebergabe-identity-mandanten.md b/docs/PROMPT-uebergabe-identity-mandanten.md new file mode 100644 index 0000000..1f268bc --- /dev/null +++ b/docs/PROMPT-uebergabe-identity-mandanten.md @@ -0,0 +1,71 @@ +# Übergabe-Prompt — Auth-Umbau „Zentrale Identität + Mandanten-Mitgliedschaften" + +> Diesen Prompt einem neuen Entwickler bzw. dessen Claude-Code-Agenten geben. Er bootstrapt in certvia und diese Aufgabe. Zugehörige Dokumente liegen im selben Branch. + +```text +Du übernimmst Entwicklungsarbeit am Produkt „certvia" (ISMS-Tool, Multi-Tenant- +Next.js-16 / Prisma-7 / Postgres+RLS / Auth.js-v5 SaaS). Repo: ~/Projects/ISMS-Tool, +Integrationsbranch `dev`. Deine Aufgabe: den Auth-Umbau „Zentrale Identität mit +Mandanten-Mitgliedschaften" (Option C) umsetzen. + +BRANCH / CHECKOUT: + Arbeits-/Doku-Branch: `identity-mandanten` + - origin = https://git.certvia.de/msolarczek/certvia.git (Branch: identity-mandanten) + - local-gitea = interner Spiegel (Branch: identity-mandanten) + Auschecken: git fetch origin && git checkout identity-mandanten + Die unten genannten docs/ liegen auf genau diesem Branch. + +WICHTIG: certvia ist strikt getrennt von jedem anderen Produkt (insb. „visitvia"). +Nichts vermischen. + +1) PFLICHTLEKTÜRE — erst lesen, nicht sofort coden, in dieser Reihenfolge: + - docs/HANDOVER-DEV.md, docs/SPEC.md (Projektgrundlagen) + - docs/STAND-dev-branch.md (aktueller Entwicklungsstand) + - docs/UEBERGABE-identity-mandanten.md (Kurzübergabe zu genau dieser Aufgabe) + - docs/FEINDESIGN-identity-mandanten.md (der umsetzbare Bauplan — dein Fahrplan) + - docs/KONZEPT-identity-mandanten.md (Warum/was, getroffene Entscheidungen A–E) + +2) AUFTRAG: + Setze Option C um. Reihenfolge = die Workstreams/Meilensteine aus dem FEINDESIGN. + Beginne mit WS0 (Fundament): neues globales `Identity`-Modell, Schema-Recut von + `User` zur Mitgliedschaft (+identityId), Migration, `TENANT_MODELS` anpassen, + Reseed. WS0 ist Blocker — bau es als Pairing und lass es reviewen. + +3) VERBINDLICHE REGELN (aus dem FEINDESIGN, nicht verhandelbar): + - `User.id` = Mitgliedschaft, STABIL lassen; Auth-Felder wandern auf `Identity`. + - `Identity` ist GLOBAL: NICHT in `TENANT_MODELS`, kein tenant_id, keine RLS-Policy. + - Genau EIN aktiver Mandant pro Session; `session.user.tenantId` = aktiver Mandant; + server-autoritativ; bei Mandantenwechsel Membership+MFA re-validieren. + - Nutzeranlage NUR per Einladung (kein „Passwort direkt setzen" mehr). + - MFA/Passwort gehören der Identity — KEIN Mandanten-Admin-Reset. + - MFA beim Login als 2. Schritt (erst E-Mail+Passwort, dann MFA); dazwischen KEINE + volle Session (kurzlebiger MFA-pending-State). + - Plattform-Admins (`platform_admins`) bleiben getrennt — nicht anfassen. + +4) ARBEITSWEISE: + - Validierungs-Gate vor JEDEM PR/Merge: `npx tsc --noEmit`, `npm run lint`, + `npm run build`, und ALLE `scripts/test-*.ts` müssen grün sein. Jede Story bringt + ihren eigenen Test mit (Identity-Login, Tenant-Switch-Isolation, MFA-Enforcement + multi-tenant, Einladung, Two-Step-Bypass). + - DevOps: Feature-Branch → `git merge --no-ff` nach `dev` → Gate grün → + Push auf BEIDE Remotes (origin=git.certvia.de, local-gitea) → + docs/STAND-dev-branch.md pflegen. + - Definition of Done: siehe FEINDESIGN §9. + +5) KOORDINATION: + Parallel läuft „Richtlinien-Upload im Adminportal". Funktional unabhängig, ABER + beide editieren src/app/(platform)/admin/[id]/page.tsx (Policy-Upload = Module-Karte, + Identity-Umbau = Benutzerverwaltung). Reihenfolge auf dieser Datei abstimmen. + +6) NICHT TUN: + - Getroffene Entscheidungen A–E nicht umwerfen (bei echtem Problem eskalieren, nicht + eigenmächtig ändern). + - Phase-2-Punkte (per-Mandant „immer Step-up", E-Mail-Änderung als Identity-Op, + PlatformAdmin-Konsolidierung) sind bewusst ausgeklammert — nicht mitbauen. + - Keine Datenmigration bauen: es gibt nur Testdaten → Schema-Recut + Reseed. + +Erste Schritte: (a) Pflichtlektüre lesen und mir eine 10-Zeilen-Zusammenfassung + +offene Fragen zurückgeben, (b) WS0 als PR-Plan skizzieren (Schema-Diff, Migrationen, +TENANT_MODELS-Änderung, Reseed), (c) nach Freigabe umsetzen. Warte nach (a)/(b) auf +Bestätigung, bevor du WS0 mergst. +``` diff --git a/docs/PROMPT-uebergabe-kundenbetreuung.md b/docs/PROMPT-uebergabe-kundenbetreuung.md new file mode 100644 index 0000000..6265b87 --- /dev/null +++ b/docs/PROMPT-uebergabe-kundenbetreuung.md @@ -0,0 +1,43 @@ +# Übergabe-Prompt: Kundenbetreuung certvia + +**Zweck:** Onboarding eines neuen Kundenbetreuers (Customer Success/Support). Kann direkt gelesen oder einem KI-Assistenten (z. B. Claude) als Kontext-Prompt gegeben werden. Hauptquelle im Detail: `docs/HANDBUCH-KUNDENBETREUUNG.md`. + +--- + +Rolle: Du übernimmst die Kundenbetreuung (Customer Success/Support) für „certvia" — ein Multi-Mandanten-ISMS-Tool (Informationssicherheits-Managementsystem als SaaS). Ziel: certvia-Kunden onboarden, betreuen und im Alltag unterstützen. + +Was ist certvia (in einem Satz): +Jeder Kunde ist ein eigener Mandant mit strikt getrennten Daten. Das Tool führt Kunden von der Strukturanalyse (Assets/Prozesse/Lieferanten) über Risikomanagement, Richtlinien und Maßnahmen bis zur Audit-Vorbereitung — wahlweise nach TISAX (VDA-ISA) und/oder ISO 27001. + +Deine ersten Schritte (Woche 1): +1. Lies das Handbuch: docs/HANDBUCH-KUNDENBETREUUNG.md (im Projekt-Repo). Es ist deine Hauptquelle. +2. Klick die Demo-/Testinstanz komplett durch — am besten lernt man das Produkt hands-on: + - Mandanten-Login /login: admin@demo.example / Demo1234! + - Superadmin /platform/login (MFA-Einrichtung beim ersten Login). + - Schau alle Module an: Assets, Prozesse, Risiken, Lieferanten, Maßnahmen, Richtlinien, SoA, Audit-Readiness, Vorfälle, Aufgaben. +3. Verstehe die Framework-Wahl: ein Mandant kann ISO 27001 und/oder TISAX führen (in der Admin-Konsole je Mandant aktivierbar). Unterschiede stehen im Handbuch (TISAX = Reifegrad/AL2/AL3; ISO = Anwendbarkeitserklärung/SoA + Managementklauseln). + +Deine Kernaufgaben: +- Neue Kunden beim Onboarding begleiten (Stammdaten, Framework-Wahl, Onboarding-Wizard, Erfassung der Bestandsdaten). +- Support im Alltag: Login/MFA/Passwort, Rollen & Rechte, Module, Vorlagen/Richtlinien. +- Fachliche Beratung „welche Norm passt" (ISO vs. TISAX) auf Basis des Handbuchs. + +Typische Support-Fälle (Details im Handbuch §7): +- „Anmeldung fehlgeschlagen": richtige Seite (/login vs /platform/login), Passwort exakt, ggf. kurze Sperre nach 5 Fehlversuchen (15 Min). +- „MFA-Gerät verloren": Recovery-Codes; sonst MFA administrativ zurücksetzen. +- „Modul fehlt": in der Admin-Konsole für den Mandanten aktivieren. +- „ISO/TISAX fehlt": Framework des Mandanten prüfen/aktivieren. + +Grenzen & Eskalation (wichtig): +- Niemals Kundendaten zwischen Mandanten kopieren (Mandantentrennung/Datenschutz). +- Keine eigenmächtigen Löschungen an Produktivdaten; keine Secrets per E-Mail/Chat weitergeben. +- Bei technischen Themen (Deployment, Fehlermeldungen im Betrieb, Backups, TLS/Domain, Datenbank) an das DevOps-/Entwicklerteam eskalieren — nicht selbst am Produktivsystem eingreifen. + +Wo du alles findest: +- Handbuch: docs/HANDBUCH-KUNDENBETREUUNG.md +- Produkt/Funktionsumfang: docs/SPEC.md, docs/HANDOVER-PM.md +- Feature-Konzepte: docs/KONZEPT-framework-iso27001.md (ISO/TISAX) +- Kundennahe Mockups (im Browser): docs/ISMS-Prototyp-GEFIM.html, docs/ISMS-Lieferantenmanagement-GEFIM.html +- Aktueller Stand: docs/STAND-dev-branch.md + +Arbeitsweise: Wenn du unsicher bist, prüfe zuerst im Handbuch und in der Demo-Instanz. Dokumentiere wiederkehrende Support-Fälle, damit das Handbuch wächst. diff --git a/docs/SEC1-MAIL.md b/docs/SEC1-MAIL.md new file mode 100644 index 0000000..7f00312 --- /dev/null +++ b/docs/SEC1-MAIL.md @@ -0,0 +1,177 @@ +# SEC1 — SMTP-Mail-Fundament + +> Branch `dev-sec1-mail-smtp` (Basis `dev`) · Grundlage: `docs/sicherheit/SEC1-Mail-Fundament-Detail.md` +> Fundament für Passwort-Reset (SEC2), Einladung (SEC4), MFA-Hinweise (SEC3) und +> Ticket-/Freigabe-/Fristen-Benachrichtigungen. + +--- + +## 1. Architektur + +``` +Aufrufer (Server-Action / Event) + │ enqueueMail({template,to,vars,tenantId,locale,dedupeKey}) + ▼ +service.ts ──► MailLog(pending) Worker-Prozess (npm run worker:mail) + │ (dedupeKey = Sperre) ┌──────────────────────────────────┐ + ├─ Queue erreichbar? ──ja──► Redis ──►│ BullMQ "mail" │ + │ │ → renderTemplate(locale) │ + └─ nein ─────────────────────────────►│ → provider.send() (deliver.ts) │ + (inline, gleicher deliver-Pfad) │ → MailLog(sent|failed) │ + │ → Retry/Backoff → mail-dead-letter + └──────────────────────────────────┘ + Provider-Interface ← SMTP (nodemailer, Pool + TLS) +``` + +Vier Schichten, wie im Aufgabenpaket vorgesehen: **Provider** (`provider.ts`, +`provider-smtp.ts`), **Templates** (`templates.ts` + `src/lib/email-brand.ts`), +**Queue/Worker** (`queue.ts`, `worker.ts`), **Service/Trigger** (`service.ts`, +`notifications.ts`). + +--- + +## 2. Betriebsmodus (Entscheidung) + +Das Aufgabenpaket verlangt eine Festlegung — hier ist sie: + +| `REDIS_URL` | Modus | Verhalten | +|---|---|---| +| gesetzt **und** erreichbar | **Queue** (Produktivmodus) | Asynchron über BullMQ; ein **eigener Worker-Prozess** (`npm run worker:mail`, eigener Container in Coolify) stellt zu. Retry mit exponentiellem Backoff (5 Versuche), Dead-Letter-Queue, Limiter (20 Mails/10 s, Concurrency 5), Graceful Shutdown. | +| gesetzt, aber **nicht erreichbar** | Inline (degradiert) | Der Versand fällt auf den direkten Pfad zurück, damit bei einem Redis-Ausfall keine Mail verloren geht — **ohne** Retry/DLQ. Wird im Log vermerkt. | +| nicht gesetzt | Inline | Lokale Entwicklung und Demo laufen ohne Redis. | + +Die Erreichbarkeit wird **vor** dem Einstellen geprüft (`isQueueReady()`). Ein +Fallback *nach* einem fehlgeschlagenen `add()` wäre riskant: der Job könnte +angekommen sein und nur die Bestätigung verloren gegangen — das ergäbe einen +Doppelversand. Deshalb wird ein Fehler beim Einstellen nur protokolliert. + +Der Worker registriert zusätzlich den **Fristen-Job** (täglich 07:00 +Europe/Berlin) auf einer **eigenen** Queue `mail-scheduler`. Grund: ein +BullMQ-Worker konsumiert alle Jobs *seiner* Queue unabhängig vom Job-Namen — +auf einer gemeinsamen Queue könnte der Zustell-Worker den Fristen-Job abgreifen. + +--- + +## 3. Konfiguration + +Führend sind die bereits im Repo etablierten Namen; die im Aufgabenpaket +genannten Aliasse werden zusätzlich akzeptiert. + +| Variable | Alias | Zweck | +|---|---|---| +| `SMTP_HOST`, `SMTP_PORT` | — | Relay | +| `SMTP_SECURE` | — | `true` = implizites TLS (465), sonst STARTTLS. Ohne Angabe aus dem Port abgeleitet. | +| `SMTP_USER`, `SMTP_PASSWORD` | `SMTP_PASS` | Authentifizierung (optional) | +| `SMTP_FROM` | `MAIL_FROM` | Absenderadresse | +| `MAIL_FROM_NAME` | — | Anzeigename (Default `Certvia`) | +| `MAIL_REPLY_TO` | — | optionale Antwortadresse | +| `APP_BASE_URL` | `AUTH_URL` | Basis für absolute Links in Mails | + +**Fehlt die Konfiguration, wird nicht still versendet:** `getMailConfig()` +liefert `null` samt Begründung, das MailLog bleibt `pending` mit Fehlertext, und +die Admin-Konsole zeigt „Nicht konfiguriert". TLS wird erzwungen — gelockert nur +gegen `localhost`/`mailpit`/`mailhog`, weil der lokale Test-SMTP kein gültiges +Zertifikat hat. + +--- + +## 4. Datenmodelle + +- **`MailLog`** — Versandprotokoll: Empfänger, Template, Locale, Status + (`pending|sent|failed|bounced|suppressed`), `providerMessageId`, Fehlertext, + Versuchszähler, `dedupeKey` (unique). `tenantId` nullable für Plattform-Mails + (`scope=platform`, analog `AuditLog`). + **Bewusst nicht gespeichert:** Mail-Inhalt und jegliche Tokens. +- **`NotificationPreference`** — je Nutzer und Ereignistyp. **Default opt-in:** + fehlt die Zeile, wird versendet; erst ein ausdrückliches `email = false` + unterdrückt. Die Pflege-UI folgt später — Modell und Auflösung stehen. + +Beide in `TENANT_MODELS` und unter RLS (ENABLE + FORCE + `USING`/`WITH CHECK`, +Migration `20260730180000_mail_fundament`, inkl. `GRANT` für `isms_app`). + +--- + +## 5. Templates + +Acht Templates, jeweils **de und en**, **HTML und Text**: +`invitation`, `password_reset`, `password_changed`, `email_change_verify`, +`email_changed_notice`, `mfa_changed`, `notification`, `test`. + +Layout, Farben und die Fußzeile „Certvia — ein Produkt von GEFIM" kommen aus +`src/lib/email-brand.ts` (Inline-Styles, Tabellenlayout für Outlook, absolute +Asset-URLs). + +**i18n-Abweichung mit Begründung:** die Sprachen liegen in einem eigenen +Katalog (`src/server/mail/templates.ts`), nicht in `messages/*.json`. Die Mails +werden im **Worker** gerendert — außerhalb eines Requests; die +next-intl-Server-APIs (`getTranslations`) setzen einen Request-Scope voraus und +stehen dort nicht zur Verfügung. + +**Tokens:** Templates bekommen fertige `actionUrl`s. Erzeugt werden die Tokens +in SEC2/SEC3/SEC4 — sie erscheinen weder im MailLog noch im Server-Log. + +--- + +## 6. Benachrichtigungen + +| Ereignis | Auslöser | Empfänger | +|---|---|---| +| `task_assigned` | `createTask`, `updateTask` (nur bei **Wechsel** des Zuständigen) | neuer Zuständiger | +| `task_approval_requested` | `submitForApproval` (Richtlinien) | ausgewählter Freigeber | +| `task_decided` | `approveTask` / `rejectTask` | Einreicher | +| `task_due` | Fristen-Job (täglich) | Zuständiger | + +Regeln: strikt mandantenisoliert, Sprache je Empfänger (Präferenz → Mandanten- +Locale → `de`), **kein Selbstversand** über die eigene Handlung, Idempotenz über +`dedupeKey` (der Fristen-Job hängt das Datum an → höchstens eine Erinnerung je +Aufgabe und Tag). Fehler beim Versand werden geloggt, kippen aber nie die +auslösende Fachaktion. + +Benachrichtigungen tragen einen Präferenzhinweis in der Fußzeile; +sicherheitsrelevante Transaktionsmails (Reset, Passwortwechsel) bewusst **nicht** +— sie sind nicht abbestellbar. + +--- + +## 7. Admin-Testversand + +`/admin` zeigt Konfigurationszustand, Modus (Queue/inline) und die letzten zehn +MailLog-Zeilen; der Button „Test-Mail senden" schickt an die **eigene** Adresse +des angemeldeten Plattform-Admins (kein Empfängerfeld — die Funktion ist eine +Zustellprüfung, kein Relay). Autorisierung über `requirePlatformSession()`; +`mail.ts` ist in `scripts/check-module-guards.ts` als `EXEMPT` registriert. + +--- + +## 8. Verifikation + +```bash +docker compose up -d mailhog # SMTP :1025, Weboberfläche :8025 +npx tsx scripts/test-mail.ts # Abnahmetest +``` + +Der Test prüft: Rendering aller Templates in de/en (HTML + Text, Branding + +Dachmarken-Fußzeile), Präferenzhinweis nur bei Benachrichtigungen, echten +Versand mit `MailLog=sent` + `providerMessageId`, Idempotenz über `dedupeKey` +und das Verhalten bei fehlender SMTP-Konfiguration. + +Nachgewiesen am 30.07.2026 gegen Mailhog: alle Prüfungen grün, Nachricht kommt +als `multipart/alternative` (HTML + Text) mit Absender `Certvia <…>`, +`Auto-Submitted: auto-generated` und korrekter Fußzeile an. + +Zusätzlich: `npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check). + +--- + +## 9. Offene Punkte / Vorbedingungen + +- **DNS:** SPF, DKIM und DMARC für die Absenderdomain müssen **vor** dem ersten + Produktivversand aktiv sein (Ops, kein Code). +- **Bounce-Verarbeitung:** `MailLog.status` kennt `bounced`, es gibt aber noch + keinen Rückkanal (Webhook/IMAP). Erst mit einem Provider sinnvoll, der + Bounces meldet. +- **Präferenz-UI:** `NotificationPreference` ist modelliert und wird ausgewertet; + die Pflegeoberfläche im Profil fehlt noch. +- **Worker-Deployment:** `npm run worker:mail` muss in + `docker-compose.coolify.yml` als eigener Service ergänzt werden (der + vorhandene `worker`-Service im lokalen Compose zeigt noch auf keinen Befehl). diff --git a/docs/SEC2-AUTH-SELFSERVICE.md b/docs/SEC2-AUTH-SELFSERVICE.md new file mode 100644 index 0000000..aef81da --- /dev/null +++ b/docs/SEC2-AUTH-SELFSERVICE.md @@ -0,0 +1,154 @@ +# SEC2 — Passwort-Self-Service, E-Mail-Änderung, Sessions + +> Branch `dev-sec2-auth-selfservice` (Basis `dev-sec1-mail-smtp`) · Grundlage: +> `docs/sicherheit/SEC2-Auth-SelfService-Detail.md` · **Abhängigkeit: SEC1** +> (Templates `password_reset`, `password_changed`, `email_change_verify`). + +Gilt durchgängig für **beide** Auth-Domänen: Mandanten-Nutzer (`/login`) und +Plattform-Admins (`/platform/login`). + +--- + +## 1. Token (`AuthToken`) + +| Eigenschaft | Umsetzung | +|---|---| +| Erzeugung | 32 Byte CSPRNG, base64url | +| Speicherung | **nur** SHA-256-Hash (`token_hash`, unique) — das Rohtoken existiert ausschließlich im Link | +| Vergleich | konstante Zeit (`timingSafeEqual`) | +| Gültigkeit | 60 Minuten (Reset und E-Mail-Verify) | +| Single-use | `usedAt` per bedingtem `updateMany` (`usedAt: null`) → zwei parallele Einlösungen können nicht beide gewinnen | +| Neuanforderung | entwertet offene Tokens desselben Typs | +| Domänen | `principalType` = `tenant_user` \| `platform_admin`; `tenantId` nur bei Mandanten-Nutzern (trägt die RLS) | + +Der Lookup beim Einlösen läuft über den **rohen** `prisma`-Client: Der Nutzer ist +zu diesem Zeitpunkt nicht angemeldet, es gibt also keinen Mandantenkontext. Die +RLS-Policy bleibt als zweite Verteidigungslinie bestehen (Migration +`20260730190000_auth_tokens_sessions`). + +--- + +## 2. Session-Invalidierung (`sessionsValidAfter`) + +NextAuth v5 arbeitet hier mit **JWT (stateless)** — es gibt keine Session-Tabelle +zum Leeren. Stattdessen trägt jedes Konto eine Versionsmarke: + +- `sessionsValidAfter` wird gesetzt → jedes JWT mit älterem `iat` gilt als ungültig. +- Geprüft dort, wo der Kontostatus **ohnehin** aus der DB gelesen wird — ohne + zusätzliche Abfrage: + `(app)/layout.tsx` (Seitenaufrufe), `moduleGuard` (Mutationen), + `requirePlatformSession()` (Plattform). +- Ohne `iat` wird **fail-closed** entschieden. + +| Funktion | Wirkung | +|---|---| +| `invalidateSessions()` | alle Sitzungen — Passwort-Reset, E-Mail-Änderung, Deaktivierung | +| `invalidateOtherSessions()` | Marke auf *eine Sekunde vor jetzt* → alle älteren Tokens fallen, die laufende Sitzung überlebt (Selbständerung) | + +Der Sekundenversatz ist kein Zufall: `iat` hat Sekundenauflösung. Ohne ihn würde +sich ein Nutzer bei der eigenen Passwortänderung selbst aussperren. + +*Offen (P1, bewusst nicht in SEC2):* „aktive Sitzungen anzeigen und einzeln +abmelden" — dafür bräuchte es Session-Records statt reiner JWTs. + +--- + +## 3. Abläufe + +### 3.1 Passwort vergessen (`/forgot-password`, `?domain=platform`) + +- Antwort **immer identisch**, unabhängig davon, ob das Konto existiert. +- Rate-Limit: 5 pro Stunde, je **IP** und je **Konto** getrennt gezählt. +- Reset nur bei aktivem, nicht gesperrtem Konto. Deaktivierte Konten bekommen + weder Mail noch abweichende Meldung. +- Mandantenseite: existiert die Adresse in **mehreren** Mandanten, ist sie nicht + eindeutig auflösbar → kein Reset (nach außen nicht unterscheidbar). + +### 3.2 Einlösung (`/reset?token=…`) + +- Die Seite **prüft** den Token nur; verbraucht wird er erst beim Absenden — + sonst würde ein Link-Scanner im Mailserver den Link entwerten. +- Ein **Policy-Verstoß entwertet den Link nicht**: geprüft wird vor dem + Verbrauch, sonst wäre der Nutzer nach einem Tippfehler ausgesperrt. +- Danach: Argon2id-Hash setzen, `mustChangePassword` löschen, Fehlversuchszähler + und Sperre zurücksetzen, **alle Sessions invalidieren**, Bestätigungsmail, + Audit (ohne Token). +- **Kein Auto-Login** — der Nutzer meldet sich neu an. + +### 3.3 Passwort selbst ändern (`/account`, `/platform/profile`) + +Alt-Passwort verifizieren (generische Fehlermeldung, Rate-Limit), Policy prüfen, +danach **andere** Sitzungen abmelden — die aktuelle bleibt. Bestätigungsmail + Audit. + +### 3.4 E-Mail-Änderung (Double-Opt-in) + +Alt-Passwort bestätigen → Verifizierungslink an die **neue** Adresse → Klick +setzt die Adresse, entwertet alle Sessions (die Adresse ist die Login-Identität) +und informiert die **alte** Adresse. Die Kollisionsprüfung läuft zweimal (bei +Anforderung und bei Bestätigung), weil die Adresse zwischenzeitlich vergeben +worden sein kann. Ob sie frei ist, wird nach außen nie gemeldet. + +--- + +## 4. Rate-Limiting + +`src/server/rate-limit.ts`, je Aktion getrennte Fenster, Schlüssel gehasht +abgelegt (kein Klartext von Adressen oder IPs im Speicher): + +| Aktion | Limit | +|---|---| +| Reset-Anfrage | 5 / Stunde | +| Reset-Einlösung | 10 / 15 Min | +| Alt-Passwort-Prüfung | 10 / 15 Min | +| E-Mail-Änderung anfordern | 5 / Stunde | + +**Bewusste Einschränkung:** Die Zähler liegen im Prozessspeicher, sind bei +mehreren App-Instanzen also pro Instanz. Das ist vertretbar, weil der Limiter +hier nur eine erste Bremse ist — die eigentlichen Garantien (single-use-Tokens, +Enumeration-Neutralität, Konto-Lockout aus F-05) hängen nicht daran. Ein +geteilter Redis-Zähler gehört zu **SEC5**. + +--- + +## 5. Erreichbarkeit + +`/forgot-password`, `/reset` und `/verify-email` sind in `src/proxy.ts` als +öffentliche Pfade eingetragen — der Nutzer ist dort per Definition nicht +angemeldet. Ihre Absicherung sind Rate-Limit, Enumeration-Neutralität und +single-use-Tokens, nicht das Route-Gate. + +--- + +## 6. Verifikation + +```bash +npx tsx scripts/test-auth-selfservice.ts # Token-, Limit- und Session-Eigenschaften +npx tsx scripts/test-reset-flow.ts # End-to-End gegen ein Wegwerf-Konto +``` + +Nachgewiesen am 30.07.2026, alle Prüfungen grün: + +- Token liegt nur gehasht in der DB (SHA-256, 64 Hex), Rohtoken nie. +- Single-use, Ablauf, Manipulation, Typ-Verwechslung und Neuanforderung greifen. +- Rate-Limit blockt ab dem 6. Versuch, auch von wechselnder IP bei gleichem Konto. +- Session-Marke: älteres JWT ungültig, neueres gültig, ohne `iat` fail-closed. +- Kompletter Reset-Zyklus: Passwort gewechselt, altes ungültig, Sessions + entwertet, Bestätigungsmail versendet, Audit ohne Token, zweite Einlösung + abgewiesen, deaktiviertes Konto ohne Token. +- Browser: `/reset` mit gültigem Link zeigt das Formular samt Mandanten-Policy, + mit manipuliertem Link die generische Ablehnung. + +Dazu `npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check). + +--- + +## 7. Offene Punkte + +- **Step-up-Re-Auth** für die E-Mail-Änderung und weitere kritische Aktionen → + **SEC3** (aktuell reicht die Alt-Passwort-Bestätigung). +- **Breach-Check** (HaveIBeenPwned) beim Setzen eines Passworts → **SEC5**; der + Aufrufpunkt liegt in `redeemPasswordReset`/`changePasswordSelf` bereit. +- **Geteiltes Rate-Limit** über Redis → SEC5. +- **Aktive Sitzungen anzeigen/einzeln abmelden** (braucht Session-Records) → P1. +- **Wartungsjob** für `purgeExpiredTokens()` ist implementiert, aber noch nicht + eingeplant (passt in den SEC1-Scheduler). diff --git a/docs/SECRETS-REGISTER.md b/docs/SECRETS-REGISTER.md new file mode 100644 index 0000000..5f6716d --- /dev/null +++ b/docs/SECRETS-REGISTER.md @@ -0,0 +1,78 @@ +# Secrets-Register — restore-/betriebs-kritische Schlüssel (certvia) + +> Produkt: **certvia** (ISMS-Tool). Umsetzung der Härtung §5 (`docs/KONZEPT-haertung.md`) +> und Backup-Konzept §9 (`docs/KONZEPT-backup-restore.md`). **Ops-/Governance-Dokument, kein Code.** +> Strikt getrennt von jedem anderen Produkt (insb. „visitvia") — eigene Secrets, eigener Tresor-Bereich. + +Dieses Register ist die **einzige verbindliche Übersicht**, welche Secrets es gibt, wer sie besitzt, +wie (und ob) sie rotiert werden und wo sie liegen. **Führung: ISB.** Ablageort der Werte: +**Org-Passwortmanager** (je Umgebung getrennter Ordner) **+ versiegelte Offline-Kopie**. + +## Grundregeln (gelten für ALLE Einträge) + +1. **Je Umgebung getrennt** — `test` / `dev` / `prod` haben **eigene, unterschiedliche** Werte. + Niemals einen prod-Wert in test/dev wiederverwenden (oder umgekehrt). +2. **Nie im Artefakt-Bucket** — Secrets liegen **niemals** im selben Bucket/Speicher wie die + verschlüsselten Backups oder DSGVO-Exporte. **Verlust des Keys = Verlust der Wiederherstellbarkeit.** +3. **Nie im Repo / nie im Backup-Artefakt** — kein Secret ins Git, keins ins Backup-Payload. + Verteilung nur als Coolify-Env-Secret + Passwortmanager. +4. **Versiegelte Offline-Kopie** — pro Umgebung eine versiegelte Offline-Kopie (z. B. verschlossener + Umschlag / getrennter Offline-Tresor) für den Totalausfall des Passwortmanagers. +5. **Rotation protokollieren** — jede Rotation mit Datum, Auslöser und ausführender Person im + Passwortmanager-Eintrag vermerken. + +## Register + +| Secret | Zweck | Eigentümer (Owner) | Rotierbar? | Rotationsregel je Umgebung | +|---|---|---|---|---| +| `AUTH_SECRET` | Session-/JWT-Signatur (Auth.js) | ISB / Betrieb | **Ja** | Rotation invalidiert alle aktiven Sessions (Nutzer müssen neu einloggen). Bei Verdacht auf Kompromittierung sofort, sonst periodisch (z. B. jährlich). Je Umgebung eigener Wert. | +| `MFA_ENC_KEY` | Verschlüsselung der TOTP-Secrets at-rest (AES-256-GCM) | ISB | **NEIN**¹ | **Nicht rotierbar ohne MFA-Neueinrichtung.** „Rotation" = Reset: alle Nutzer müssen MFA neu einrichten (alte TOTP-Secrets werden unlesbar). Nur bei Kompromittierung mit geplantem Reset. | +| `PASSWORD_PEPPER` | Passwort-Pepper (Argon2-`secret`, Phase 1) | ISB | **NEIN**¹ | **Nicht rotierbar ohne Passwort-Reset für alle** (kein Rehash-on-Login). „Rotation" = Reset: erzwungener Passwort-Neusatz aller Konten. Bewusst **einmalig** gesetzt (leere DBs). | +| `BACKUP_ENC_KEY` | Client-seitige Verschlüsselung des App-Backup-Exports (AES-256-GCM); Fallback `AUTH_SECRET` | ISB / Betrieb | **Bedingt**² | Neuer Key gilt nur für **neue** Artefakte; alte Backups bleiben nur mit dem **alten** Key entschlüsselbar → Altschlüssel bis Ablauf der Retention **aufbewahren**. Je Umgebung eigener Wert. | +| pgBackRest-Repo-Key (`repo-cipher-pass`) | AES-256-Verschlüsselung des Cluster-Backup-Repos (Postgres WAL/Base) | Betrieb | **Ja**³ | Rotierbar mit Repo-Rekey; alte Repos/Artefakte brauchen den Altschlüssel → bis Retention-Ende aufbewahren. Je Umgebung eigenes Repo + eigener Key. | +| `age`-Keypair | Verschlüsselung Per-Tenant-Export + DSGVO-Pakete (X25519) | ISB / DSB | **Ja**³ | Neuer Recipient gilt für **neue** Artefakte; Private Key der Alt-Keys bis Retention-Ende aufbewahren (sonst Alt-Exporte nicht entschlüsselbar). Je Umgebung eigenes Keypair. | +| restic-Repo-Passwort | Verschlüsselung des MinIO-Objekt-Backups (restic, AES-256) | Betrieb | **Ja**³ | Rotierbar (`restic key add/remove`); Altschlüssel bis Retention-Ende gültig halten. Je Umgebung eigenes Repo + eigenes Passwort. | + +¹ **Nicht-rotierbar markiert:** `PASSWORD_PEPPER` und `MFA_ENC_KEY` sind **keine** rotierbaren +Secrets im üblichen Sinn — eine „Rotation" bedeutet einen **Reset/Neuverschlüsselung** mit +Benutzer-Impact (Passwort- bzw. MFA-Neueinrichtung für alle). Deshalb **bewusst einmalig** setzen +(solange DBs leer/frisch) und wie einen Wiederherstellungsschlüssel behandeln. + +² `BACKUP_ENC_KEY` ist technisch tauschbar, aber jeder alte Backup-Stand bleibt an seinen +Erzeugungs-Key gebunden → nicht „rotieren und alten Key wegwerfen". + +³ Backup-Keys (pgBackRest / `age` / restic) sind rotierbar, aber **Altschlüssel müssen bis zum +Ende der jeweiligen Retention aufbewahrt** werden, sonst werden ältere Backups unwiederherstellbar. + +## ⚠ Restore-Kohärenz (verbindliche Vorbedingung) + +**`PASSWORD_PEPPER`, `MFA_ENC_KEY` und `BACKUP_ENC_KEY` sind Umgebungs-Secrets und stehen NICHT +im Backup-Artefakt.** Ein Restore in eine Umgebung mit **anderen** Secrets bricht: + +- **anderer `PASSWORD_PEPPER`** → **alle** Passwort-Prüfungen schlagen fehl (kein Login möglich). +- **anderes `MFA_ENC_KEY`** → TOTP-Secrets nicht entschlüsselbar → MFA-Prüfung bricht. +- **anderes `BACKUP_ENC_KEY`** → das AES-256-GCM-Backup-Artefakt lässt sich **gar nicht** entschlüsseln. + +**Vorbedingung vor jedem Restore** (auch im Restore-Runbook `docs/DEPLOY-PROD-CONTABO.md` verankert): +Die Zielumgebung hält **exakt die Secrets, mit denen das Backup erzeugt wurde** — oder es wird +ein **Passwort-/MFA-Reset bzw. eine Neuverschlüsselung eingeplant**. Ein Cross-Environment-Restore +(z. B. prod → staging zum Debuggen) läuft nur mit den **prod-Secrets** oder mit anschließendem Reset. + +## Ablage & Zugriff (Runbook-Kurzform) + +- **Primär:** Org-Passwortmanager, je Umgebung getrennter Ordner, Zugriff rollenbasiert (ISB + Betrieb). +- **Sekundär:** versiegelte Offline-Kopie je Umgebung (Notfall/DR). +- **Verteilung an die App:** ausschließlich als Coolify-Env-Secret (Runtime), nie ins Repo/Image. +- **Host-Encryption-Passphrase** (LUKS-Volume, s. `docs/DEPLOY-PROD-CONTABO.md`): ebenfalls hier + führen — dieselben Grundregeln (getrennt je Umgebung, offline versiegelt, nie im Backup-Bucket). +- **Bei Personalwechsel:** rotierbare Secrets (`AUTH_SECRET`, Backup-Keys) neu setzen; Zugriff im + Passwortmanager entziehen. Nicht-rotierbare (`PASSWORD_PEPPER`/`MFA_ENC_KEY`) nur bei begründetem + Kompromittierungsverdacht — dann mit geplantem Reset. + +## Bezug / Weiterführendes + +- `docs/KONZEPT-haertung.md` §5 (Register-Anforderung), §1–§3 (Pepper, Host-Encryption, Backups). +- `docs/KONZEPT-backup-restore.md` §9 (gemeinsames Verschlüsselungs-Primitiv, Schlüsselverwaltung). +- `docs/DEPLOY-PROD-CONTABO.md` (Host-Encryption + verschlüsselte Backups + Restore-Kohärenz, Ops-Runbook). +- **Phase 2 (offen):** Upgrade-Pfad auf **HashiCorp Vault** / Provider-**KMS** (Rotation, Audit, + Trennung) sowie **DB-Connection-TLS** (`sslmode`) — bewusst zurückgestellt, nicht Teil dieser Lane. diff --git a/docs/SPEC.md b/docs/SPEC.md new file mode 100644 index 0000000..d22e748 --- /dev/null +++ b/docs/SPEC.md @@ -0,0 +1,310 @@ +# ISMS-Plattform – Umsetzungsspezifikation + +> **Version 1.2** · Ergänzt gegenüber 1.1: **Assets & BIA als ein gemeinsames Modul**, zugeordnete Risiken in Asset-/Prozess-Detailansichten, ausgearbeitete **Risiko-Detailansicht** (Maßnahmen, betroffene Assets, Control-Verknüpfung, Verlauf). +> +> Diese Datei ist die Projekt-Spec für die Umsetzung durch Claude Code. +> Sie beschreibt **Architektur, Datenmodell, Module, Rollen, API und Akzeptanzkriterien**. +> Sprache der Anwendung: **Deutsch (i18n-fähig, EN vorbereitet)**. + +## 0. Kontext & Leitentscheidungen + +Es wird eine Web-Applikation zum Betrieb eines Informationssicherheits-Managementsystems (ISMS) entwickelt, die von mehreren Kunden (Mandanten) mit mehreren Nutzern und Rollen genutzt wird. Ausrichtung auf **ISO/IEC 27001:2022** und **TISAX / VDA-ISA 6.0**. + +Getroffene Entscheidungen (aus Anforderungsklärung): + +| Thema | Entscheidung | +|---|---| +| Betriebsmodell | Zentrale SaaS, **Multi-Tenant** (gemeinsame DB, Mandanten-ID + strikte Row-Level-Trennung) | +| Container | Betrieb in Docker (Compose), horizontal skalierbar | +| KI / Assistent + Chat | **Cloud-LLM** (Anthropic/OpenAI) über austauschbaren Provider-Adapter | +| Tech-Stack | Modernes Web-Frontend, Technologie offen → **empfohlener Stack unten** | +| Authentifizierung | **Lokale Accounts (MVP)** mit RBAC; SSO (OIDC/SAML) als spätere Erweiterung vorbereiten | +| Umfang | Alle Module gleichwertig (kein hartes Phasing), aber sinnvolle Iterationsreihenfolge | +| Norm-Inhalte | **ISO 27001:2022 Annex A (93 Controls)** vorbefüllt + SoA; **VDA-ISA** Struktur/Mapping vorbereitet, Katalog-Inhalte per Import (lizenzrechtlich, siehe §12) | +| Sprache | Deutsch, i18n-ready | +| UX | Modern, einfach, geringe Komplexität, Drag-and-Drop, grafische Oberflächen | + +## 1. Empfohlener Tech-Stack + +Ziel: **eine** Codebasis, geringe Betriebs- und Wartungskomplexität, moderne UX. + +- **Frontend & Backend:** Next.js 15 (App Router, React 19, TypeScript) — SSR + API in einem Deployment. +- **API-Layer:** tRPC (typsicher) oder REST (OpenAPI). Empfehlung: tRPC intern, zusätzlich schlanke REST-Endpunkte für Integrationen/Webhooks. +- **ORM/DB:** Prisma + **PostgreSQL 16**. Vektorsuche für den Chat/RAG über **pgvector** (kein zusätzlicher Vektor-DB-Dienst nötig). +- **Auth:** Auth.js (NextAuth) mit Credentials-Provider (lokale Accounts), Argon2id-Hashing, TOTP-2FA. OIDC/SAML-Provider als Feature-Flag vorbereitet. +- **Hintergrundjobs / wiederkehrende Aufgaben:** BullMQ + Redis (Scheduler für Reviews, Audits, Fristen, Erinnerungen). +- **Dateispeicher:** S3-kompatibel (MinIO im Compose-Stack), verschlüsselt. +- **UI-Kit:** Tailwind CSS + shadcn/ui, Icons via lucide-react, Diagramme via Recharts. +- **Drag-and-Drop:** dnd-kit (Kanban-Boards, Risiko-Matrix-Einordnung, Aufgaben, Datei-Uploads). +- **KI-Anbindung:** Provider-Adapter (`AiProvider`-Interface) für Anthropic/OpenAI; RAG-Pipeline auf Dokumenten des Mandanten. +- **E-Mail:** SMTP (Benachrichtigungen, Fristen, Eskalationen). +- **Tests:** Vitest (Unit), Playwright (E2E). Linting: ESLint + Prettier. + +> Alternative bei starkem KI-/Analytics-Fokus: zusätzlicher **Python-FastAPI-Microservice** nur für RAG/Embedding. Für geringe Komplexität zunächst **nicht** empfohlen — alles in Next.js. + +## 2. Architektur (High-Level) + +``` + ┌─────────────────────────────────────────────┐ + Browser ───▶ │ Next.js (App Router) │ + (DE UI) │ - React UI (Tailwind + shadcn/ui, dnd-kit) │ + │ - tRPC/REST API │ + │ - Auth.js (RBAC, Mandanten-Guard) │ + └───────┬───────────────┬──────────────┬───────┘ + │ │ │ + Prisma BullMQ AiProvider + │ (Worker) (Adapter) + ┌───────▼───────┐ ┌───▼────┐ ┌────▼─────────┐ + │ PostgreSQL 16 │ │ Redis │ │ Anthropic / │ + │ + pgvector │ │ │ │ OpenAI API │ + └───────────────┘ └────────┘ └──────────────┘ + ┌───────────────┐ + │ MinIO (S3) │ Dokumente, Nachweise, Uploads + └───────────────┘ +``` + +**Mandantenfähigkeit (Multi-Tenant):** Jede fachliche Tabelle trägt `tenant_id`. Zugriff ausschließlich über einen zentralen Prisma-Middleware-/Query-Guard, der `tenant_id` aus der Session erzwingt (Row-Level-Isolation). Zusätzlich Postgres **Row Level Security (RLS)** als zweite Verteidigungslinie. Kein Query ohne Mandantenkontext. + +## 3. Rollen- und Rechtemodell (RBAC) + +Rollen sind pro Mandant vergeben. Ein Nutzer kann mehrere Rollen haben. + +| Rolle | Beschreibung | Kernrechte | +|---|---|---| +| **Plattform-Admin** (mandantenübergreifend) | Betreiber der SaaS | Mandanten anlegen/sperren, globale Kataloge pflegen, keine Einsicht in Kundendaten außer für Support (protokolliert) | +| **Mandanten-Admin** | Kundenadministrator | Nutzer/Rollen im Mandanten verwalten, Stammdaten, Konfiguration | +| **ISB / CISO** | Informationssicherheitsbeauftragter | Vollzugriff fachlich: Risiken, Assets, BIA, Maßnahmen, Vorfälle, Freigaben, Chat-Eskalationsziel | +| **Auditor** (intern/extern) | Prüfer | Lesezugriff + Audit-Durchführung, Findings anlegen, keine Bearbeitung der Fachdaten | +| **Asset-/Risk-Owner** | Fachverantwortliche | Bearbeitung zugewiesener Assets/Risiken/Maßnahmen | +| **Mitarbeiter / User** | Standardnutzer | Chat nutzen, Richtlinien lesen, Vorfälle melden, eigene Aufgaben | + +Rechte werden als granulare **Permissions** (`asset:read`, `risk:write`, `incident:manage`, …) implementiert und über Rollen gebündelt. UI blendet nicht-erlaubte Aktionen aus; API prüft serverseitig. + +## 4. Module (funktionaler Kern) + +### 4.1 Assets & BIA (ein gemeinsames Modul) + +Asset-Inventar und Business Impact Analyse bilden **ein zusammenhängendes Modul** (gemeinsamer Navigationsbereich, durchgängige Detailansichten). Assets, Prozesse und deren Kritikalität werden im selben Kontext gepflegt. + +#### 4.1.1 Asset-Inventar +Zentrales Verzeichnis aller Werte (Assets): Informationen, Systeme, Anwendungen, Standorte, Lieferanten, Personen/Rollen, Datenkategorien. + +- Attribute: Name, Typ, Owner, Standort/Prozesszuordnung, Klassifizierung (C/I/A — Vertraulichkeit/Integrität/Verfügbarkeit als Schutzbedarf 1–4), Lieferanten/Verantwortliche, Status, Tags. +- Beziehungen zwischen Assets (Abhängigkeiten) modellierbar → speist BIA und Risiko. +- Import/Export (Excel/CSV), Bulk-Bearbeitung, Versionshistorie. +- **Grafische Ansicht:** filterbare Tabelle + optionale Abhängigkeits-/Netzwerkgrafik. +- **Asset-Detailansicht** zeigt neben Stammdaten und Beziehungen auch: + - **Zugeordnete Risiken** (mit Risikowert, Status, Behandlung) inkl. Absprung in die Risiko-Detailansicht, + - zugeordnete Prozesse (mit Rolle primär/sekundär) und daraus vererbter Schutzbedarf, + - verknüpfte Maßnahmen, Vorfälle und Nachweise. + +#### 4.1.2 Business Impact Analyse (BIA) +Ermittelt Kritikalität von Prozessen/Assets und Wiederanlaufparameter. + +- Erfassung von Geschäftsprozessen, Zuordnung zu Assets. +- **Asset-Rollen je Prozess (Detailansicht):** In der Prozess-Detailansicht werden die zugeordneten Assets nach Rolle unterschieden: + - **Primäres Asset** = das im Prozess erzeugte/verantwortete Ergebnis-Asset (z. B. der erzeugte Datensatz/das Informationsobjekt). Genau ein oder wenige je Prozess. + - **Sekundäre Assets** = alle unterstützenden Assets, die zur Prozessdurchführung benötigt werden (Systeme, Anwendungen, Infrastruktur, Personen/Rollen, Lieferanten). + - Die Rollenzuordnung speist die Abhängigkeitsanalyse (siehe 4.11) und die Schutzbedarfsvererbung: Der Schutzbedarf des primären Assets/Prozesses vererbt sich auf die sekundären Assets (max. Prinzip). +- Schadensszenarien und Schadenshöhe je Schutzziel und Zeitverlauf. +- Kennzahlen: **RTO, RPO, MTD/MTPD**, maximal tolerierbarer Ausfall. +- Ergebnis: Kritikalitätsstufe je Prozess/Asset → priorisiert Risikoanalyse und Maßnahmen. +- **Prozess-Detailansicht** zeigt zusätzlich die **zugeordneten Risiken** des Prozesses und seiner Assets (aggregiert, mit Risikowert und Status). +- Geführter Wizard (Schritt-für-Schritt), Ergebnis als Report exportierbar. + +### 4.2 Risikoanalyse & -behandlung +Aufbauend auf Assets + BIA. + +- Risiken = (Asset/Prozess) × Bedrohung × Schwachstelle. +- Bewertung: Eintrittswahrscheinlichkeit × Auswirkung → Risikowert; konfigurierbare Skalen (z. B. 5×5). +- **Interaktive Risiko-Matrix (Heatmap)** mit Drag-and-Drop-Einordnung/Filter. +- Risikobehandlung: Vermeiden / Vermindern / Übertragen / Akzeptieren; Maßnahmen (Controls) verknüpfen. +- Rest-Risiko nach Maßnahme, Risikoakzeptanz mit Freigabe-Workflow (ISB/Leitung). +- Vererbung: Schutzbedarf aus Asset/BIA wird vorbelegt. +- Verknüpfung zu ISO-27001-Annex-A-Controls und VDA-ISA-Zielen (SoA-Bezug). +- **Risiko-Detailansicht (vollständig):** + - Stammdaten: Beschreibung, Bedrohung/Schwachstelle, Owner, Status, Termine/Reviews. + - Bewertung: Brutto-Risiko (Wahrscheinlichkeit × Auswirkung), **Rest-Risiko** nach Maßnahmen, Bewertungshistorie (Verlauf des Risikowerts über Zeit). + - **Notwendige/verknüpfte Maßnahmen:** Liste der behandelnden Maßnahmen mit Status, Fälligkeit und Owner; neue Maßnahme direkt aus dem Risiko heraus anlegbar. + - **Betroffene Assets/Prozesse:** alle verknüpften Assets und Prozesse mit Schutzbedarf/Kritikalität, Absprung in deren Detailansichten. + - Verknüpfte Annex-A-Controls / VDA-ISA-Ziele (SoA-Bezug) und ggf. auslösende Vorfälle. + - Freigabe-/Akzeptanz-Workflow mit Kommentar und Audit-Trail. + +### 4.3 Control-Kataloge & Statement of Applicability (SoA) +- **ISO 27001:2022 Annex A** mit 93 Controls in 4 Themen (Organisatorisch 37, Personenbezogen 8, Physisch 14, Technologisch 34) **vorbefüllt**. +- **SoA:** je Control Anwendbarkeit (ja/nein + Begründung), Umsetzungsstatus, Verweise auf Maßnahmen/Nachweise, Verantwortliche. +- **VDA-ISA 6.0**: 9 Kapitel/Prüfziele als Struktur + Mapping-Tabelle ISO↔VDA-ISA (siehe §12 zur Lizenz). +- Reifegrad-Bewertung (VDA-ISA-Reifegradmodell 0–5) je Prüfziel. + +### 4.4 Maßnahmenverwaltung (Controls/Tasks) +- Maßnahmen mit Owner, Fälligkeit, Status, Priorität, Nachweisen (Dateien). +- **Kanban-Board (Drag-and-Drop)** und Listen-/Kalenderansicht. +- Verknüpfung zu Risiken, Controls, Vorfällen, Audits. +- **Maßnahmen-Detailansicht** zeigt die **zugeordneten Risiken** (welche Risiken behandelt diese Maßnahme, mit Risikowert vor/nach) sowie verknüpfte Controls, Vorfälle und Nachweise. + +### 4.5 Wiederkehrende Aufgaben & Fristen (Scheduler) +Automatische Erzeugung/Erinnerung für u. a.: +- **Benutzer-/Zugriffs-Review** (z. B. quartalsweise), +- **Interne Audits** und **externe Audits/Re-Zertifizierung** (Zyklen), +- **Management-Review**, Richtlinien-Review, Risiko-Review, Lieferanten-Review. +- Konfigurierbare Wiederholung (cron-artig), Zuweisung, Eskalation bei Überfälligkeit, E-Mail-Benachrichtigung, Dashboard-Fälligkeitsanzeige. + +### 4.6 Richtlinien-Management & Implementierungs-Assistent +- Richtlinien-Bibliothek mit Versionierung, Freigabe- und Lese-Bestätigungs-Workflow. +- **KI-Assistent** führt Nutzer durch die Anpassung von Muster-Richtlinien an das eigene Unternehmen. +- **Zwei Individualisierungs-Ebenen:** + 1. **Basisdaten/Metadaten:** Firmenname, verantwortliche Rollen, Geltungsbereich, Platzhalter. + 2. **Inhaltliche Anpassung der Klauseln:** Die KI formuliert und passt die eigentlichen Richtlinientexte (Klauseln/Abschnitte) auf Basis der Unternehmensangaben an (z. B. erlaubte Geräte, Fristen, Verantwortlichkeiten, branchenspezifische Anforderungen). Vorschläge sind akzeptier-/verwerfbar. +- **Inline-Editor (WYSIWYG):** Nutzer bearbeiten die generierten Klauseltexte direkt im Tool; KI-Assistenz („umformulieren", „kürzen", „an Control X ausrichten") auf Absatzebene. +- **In-Tool-Darstellung:** Die Richtlinie wird innerhalb der Anwendung gerendert lesbar dargestellt (formatierte Ansicht, Inhaltsverzeichnis, verknüpfte Controls), nicht nur als Download. +- **Governance:** Versionierung mit Änderungsverlauf/Diff, Freigabe-Workflow, Lesebestätigung durch Mitarbeiter, Verknüpfung zu ISO-/VDA-Controls. +- Export als PDF/DOCX; Ablage in der Richtlinien-Bibliothek; Anbindung an den Chat (RAG) als Wissensquelle. + +### 4.7 Interaktiver Chat (RAG + Eskalation) +- Nutzer stellen Fragen; der Chat sucht per **RAG** in der Dokumentation/Richtlinien des Mandanten (pgvector) und antwortet mit Quellenangabe. +- Wenn keine belastbare Antwort/Berechtigung → **Eskalation/Ticket an den ISB** (Weiterleitung, Benachrichtigung, Nachverfolgung). +- Nur mandanten-eigene Dokumente im Kontext; keine mandantenübergreifende Vermischung. + +### 4.8 Sicherheitsvorfall-Management (Incident) +- Meldung von Vorfällen (auch niedrigschwellig durch Mitarbeiter, Formular + Chat). +- Workflow: Erfassung → Triage/Kategorisierung → Bearbeitung → Eskalation → Abschluss → Lessons Learned. +- Schweregrad, betroffene Assets, SLA/Fristen, Aufgaben, Zeitleiste, Nachweise. +- Verknüpfung zu Risiken (neue/erhöhte Risiken) und ggf. Meldepflichten-Hinweis. + +### 4.9 Dashboards & Reporting +- Rollenbezogene Dashboards (ISB, Auditor, Owner): offene Risiken, überfällige Aufgaben, SoA-Erfüllungsgrad, Reifegrade, Vorfälle. +- Exporte: SoA, Risikoregister, Maßnahmenplan, Audit-Report, Management-Review — als PDF/Excel. + +### 4.10 Audit-Management +- Audit-Plan (intern/extern), Scope, Prüfpunkte (aus Katalogen), Findings, Maßnahmen aus Findings, Nachverfolgung, Audit-Report. + +### 4.11 Abhängigkeits- & Kritische-Pfade-Analyse +Visualisiert die Verkettung von Prozessen und Assets, um Single Points of Failure und kritische Pfade sichtbar zu machen. + +- **Netzwerkgraph:** Knoten = Prozesse und Assets (primär/sekundär), Kanten = Abhängigkeiten (aus Asset-Relationen und BIA-Rollenzuordnung). +- **Kritische Pfade** werden anhand von Kritikalität/Schutzbedarf (aus BIA) berechnet und farblich hervorgehoben; Engstellen (Assets, von denen viele kritische Prozesse abhängen) werden markiert. +- Interaktiv: Filtern nach Prozess/Kritikalität, Knoten anklicken → Detail/Sprung zum Asset, Hervorheben aller abhängigen Elemente. +- Speist Risikoanalyse (Konzentrationsrisiken) und BCM/Notfallplanung. +- Umsetzungshinweis: Rendering mit einer Graph-Bibliothek (z. B. Cytoscape.js oder D3-Force); Datenbasis sind `AssetRelation` und die BIA-Primär-/Sekundär-Zuordnung. + +### 4.12 Nachweis- & Dokumentenmanagement +- Zentrale, auditfeste Ablage für Nachweise/Evidenzen (Dateien, Screenshots, Protokolle). +- Verknüpfung eines Nachweises mit Controls (SoA), Maßnahmen, Audits, Risiken und Vorfällen. +- Metadaten: Gültigkeit/Ablaufdatum, Verantwortliche, Version, Vertraulichkeit; Erinnerung bei ablaufenden Nachweisen. +- Volltext-/Metadatensuche; Nachweise sind Quelle für den RAG-Chat. + +### 4.13 Lieferanten- & Dienstleister-Management (Third-Party) +Für TISAX besonders relevant. + +- Verzeichnis externer Dienstleister/Lieferanten mit Kontakt, Leistungen, Kritikalität. +- Sicherheitsbewertung/Fragebögen, Zertifikatsnachweise (z. B. ISO 27001/TISAX-Label), Ablaufüberwachung. +- Vertrags-/AV-Verwaltung (DSGVO Art. 28), Wiedervorlage/Review-Zyklen (siehe wiederkehrende Aufgaben). +- Verknüpfung zu Assets (welcher Dienstleister betrifft welche Assets) und Risiken (Third-Party-Risiko). + +### 4.14 Management-Review & Kennzahlen (KPIs) +ISO-27001-Pflichtthemen zur Wirksamkeitsmessung. + +- Definierbare Kennzahlen/Metriken (z. B. SoA-Erfüllungsgrad, offene Risiken, Reaktionszeiten Vorfälle, überfällige Aufgaben, Reifegradentwicklung) mit Zielwerten und Trend. +- Strukturierte **Management-Review**-Vorlage (Eingaben, Ergebnisse, Beschlüsse, Verantwortliche, Termine) mit Historie. +- Wirksamkeitsbewertung von Maßnahmen; Export als Management-Report (PDF). + +## 5. Datenmodell (Kern-Entitäten, vereinfacht) + +Alle fachlichen Tabellen enthalten `tenant_id`, `created_at`, `updated_at`, `created_by`. + +- **Tenant**(id, name, status, config) +- **User**(id, tenant_id, email, password_hash, name, status, mfa_secret) +- **Role**(id, tenant_id, key, name) / **Permission** / **UserRole** / **RolePermission** +- **Asset**(id, tenant_id, name, type, owner_id, classification_c/i/a, status, tags) +- **AssetRelation**(asset_id, related_asset_id, type) +- **Process**(id, tenant_id, name, owner_id) — BIA-Bezug +- **ProcessAsset**(id, tenant_id, process_id, asset_id, **role** = `primary` | `secondary`) — Asset-Rolle je Prozess (BIA) +- **BiaEntry**(id, tenant_id, process_id, rto, rpo, mtd, impact_scores, criticality) +- **Threat** / **Vulnerability** (Kataloge, teils global) +- **Risk**(id, tenant_id, asset_id/process_id, threat_id, likelihood, impact, score, treatment, residual_score, owner_id, status) +- **RiskAsset**(risk_id, asset_id) — n:m betroffene Assets je Risiko (zusätzlich zum Hauptbezug) +- **RiskMeasure**(risk_id, measure_id) — n:m Risiko ↔ behandelnde Maßnahmen +- **Control**(id, framework, ref, title, theme) — global (ISO/VDA) +- **Soa**(id, tenant_id, control_id, applicable, justification, status, maturity, owner_id) +- **Measure/Task**(id, tenant_id, title, owner_id, due_date, status, priority, links[]) +- **RecurringTask**(id, tenant_id, type, schedule_cron, next_run, assignee) +- **Policy**(id, tenant_id, title, version, status, body, ack_required) +- **Document/Evidence**(id, tenant_id, name, storage_key, embedding[] via pgvector) +- **ChatSession/ChatMessage**(…, sources[], escalated_to_isb) +- **Incident**(id, tenant_id, title, severity, status, category, affected_assets[], timeline[]) +- **Audit**(id, tenant_id, type, scope, planned_date) / **Finding**(…) +- **Supplier**(id, tenant_id, name, criticality, contract_ref, av_status, cert_status, cert_expiry, review_cron) / **SupplierAsset**(supplier_id, asset_id) +- **Kpi**(id, tenant_id, name, target, unit) / **KpiValue**(kpi_id, period, value) +- **ManagementReview**(id, tenant_id, date, inputs, results, decisions, owner_id) +- **AuditLog**(id, tenant_id, actor, action, entity, before/after, timestamp) + +## 6. API-Design (Auszug) + +REST-/tRPC-Ressourcen je Modul mit CRUD + Aktionen: +`/assets`, `/bia`, `/risks`, `/controls`, `/soa`, `/measures`, `/recurring-tasks`, `/policies`, `/chat`, `/incidents`, `/audits`, `/reports`, `/admin/tenants`, `/admin/users`. + +Querschnitt: `GET /export/{modul}` (Excel/PDF), `POST /import/{modul}` (Excel/CSV), Webhooks für Fristen/Eskalationen. Jede Anfrage: Auth-Guard → Mandanten-Guard → Permission-Check → Handler → AuditLog. + +## 7. Nicht-funktionale Anforderungen + +- **Sicherheit:** Verschlüsselung at-rest (DB/Objektspeicher) und in-transit (TLS), Argon2id-Passwörter, TOTP-2FA, Session-Härtung, CSRF-/XSS-/SQLi-Schutz, striktes RBAC + Mandanten-Isolation (RLS), vollständiges Audit-Log. +- **Datenschutz (DSGVO):** Auftragsverarbeitung, Löschkonzept, Datenminimierung; für Cloud-LLM: DPA mit KI-Anbieter, konfigurierbares Opt-out des Trainings, optionale Anonymisierung sensibler Felder vor KI-Aufruf. +- **Performance:** Listen mit Server-Pagination/Filter; Zielantwortzeit < 300 ms für Standardabfragen. +- **Verfügbarkeit:** Stateless App-Container (horizontal skalierbar), Backups DB + Objektspeicher, Health-/Readiness-Endpunkte. +- **Barrierefreiheit & UX:** WCAG-AA-orientiert, responsive, konsistente Komponenten, geringe Klicktiefe. +- **i18n:** Alle UI-Texte über Message-Katalog (de default, en vorbereitet). +- **Nachvollziehbarkeit:** Versionierung von Richtlinien, Risiken, SoA; lückenloses Änderungsprotokoll (auditfest). + +## 8. Deployment (Docker) + +`docker-compose.yml` mit Services: `app` (Next.js), `worker` (BullMQ), `postgres` (pgvector-Image), `redis`, `minio`, optional `mailhog` (Dev). Konfiguration über `.env` (DB, Redis, S3, SMTP, `AI_PROVIDER`, `AI_API_KEY`). Migrations via Prisma. Seed-Skript befüllt globale Kataloge (ISO Annex A, VDA-ISA-Struktur, Threat-/Vuln-Beispiele) und einen Demo-Mandanten. + +## 9. UX-Leitlinien + +Modern, aufgeräumt, geringe Komplexität. Konsequenter Einsatz von: geführten Wizards (BIA, Richtlinien-Assistent), **Drag-and-Drop** (Kanban für Maßnahmen/Aufgaben, Risiko-Heatmap, Datei-Uploads), grafischen Auswertungen (Heatmaps, Reifegrad-Radar, Fortschrittsbalken), Inline-Bearbeitung und klaren, rollenbezogenen Startseiten. Fachbegriffe mit Tooltips erklärt. + +Das HTML-Mockup (`docs/ISMS-Prototyp-GEFIM.html`) dient als **Orientierung** für Navigation, Layout und Views — die Module werden fachlich darüber hinaus vervollständigt (z. B. Risiko-Verknüpfungen in Detailansichten, siehe §4). + +## 10. Akzeptanzkriterien (Definition of Done je Modul) + +- Ein Nutzer eines Mandanten sieht **niemals** Daten eines anderen Mandanten (durch Test nachgewiesen: RLS + Guard). +- RBAC serverseitig erzwungen; UI blendet unerlaubte Aktionen aus. +- Asset → BIA → Risiko → SoA/Maßnahme bilden eine durchgängige, verknüpfte Kette — in beide Richtungen navigierbar (Asset zeigt Risiken, Risiko zeigt Maßnahmen/Assets, Maßnahme zeigt Risiken). +- Wiederkehrende Aufgaben erzeugen automatisch Instanzen, benachrichtigen und eskalieren bei Überfälligkeit. +- Chat beantwortet Fragen mit Quellen aus Mandanten-Dokumenten und eskaliert korrekt an den ISB. +- Incident-Workflow von Meldung bis Abschluss inkl. Zeitleiste und Nachweisen. +- Exporte (SoA, Risikoregister, Audit-Report) erzeugen valide PDF/Excel. +- E2E-Tests (Playwright) für die Kernpfade grün; Audit-Log erfasst alle schreibenden Aktionen. + +## 11. Empfohlene Umsetzungsreihenfolge (Iterationen) + +Auch wenn Module gleichwertig sind, minimiert diese Reihenfolge das Risiko: + +1. **Fundament:** Projektsetup, Docker-Compose, Auth (lokale Accounts), Mandanten-Isolation (RLS + Guard), RBAC, Audit-Log, i18n-Gerüst. +2. **Kern-Fachdaten:** Assets & BIA (ein Modul) → Risikoanalyse (inkl. Heatmap + Detailansicht). +3. **Compliance:** ISO-Annex-A-Katalog + SoA, VDA-ISA-Struktur + Mapping, Reifegrade. +4. **Betrieb:** Maßnahmen-Kanban, wiederkehrende Aufgaben/Scheduler, Benachrichtigungen. +5. **Vorfälle:** Incident-Management inkl. Meldeformular. +6. **KI:** RAG-Chat mit Eskalation, Richtlinien-Implementierungs-Assistent. +7. **Auswertung:** Dashboards, Reporting/Exporte, Audit-Management. +8. **Härtung:** Sicherheits-/Datenschutz-Review, Tests, Doku. + +## 12. Lizenz-/Rechtshinweis zu Katalog-Inhalten (empfohlenes Vorgehen) + +- **ISO 27001:2022** Control-**Titel/Referenzen** (Annex A, A.5–A.8) können als Katalog abgebildet werden; der **volle Normtext** ist urheberrechtlich geschützt und darf nicht mitgeliefert werden. → Nur Kurzbezeichnungen + eigene Umsetzungshinweise, Volltext verweist der Kunde auf seine erworbene Norm. +- **VDA-ISA 6.0 / TISAX:** Der ISA-Katalog wird vom VDA/ENX bereitgestellt (ISA6 als Excel). Empfehlung: **Struktur (9 Kapitel/Prüfziele) und Mapping** abbilden, die konkreten Katalog-Inhalte per **Import** aus der offiziellen ENX-Datei einspielen (Import-Funktion für `ISA6-EN.xlsx`). So bleibt die Anwendung lizenzkonform und aktualisierbar. +- **Mapping ISO 27001 ↔ VDA-ISA** als pflegbare Tabelle vorsehen (Controls beeinflussen mehrere Prüfziele und umgekehrt). + +## 13. Offene Punkte / spätere Erweiterungen + +- SSO (OIDC/SAML, z. B. Entra ID) — Feature-Flag bereits vorgesehen. +- Self-hosted-LLM-Option je Mandant (falls Datenschutzanforderungen es verlangen). +- Meldepflichten-Assistent (NIS2/DSGVO-Fristen) im Incident-Modul. +- Mobile App / PWA für Vorfallmeldung. + +--- + +### Quellen +- VDA-ISA / TISAX Katalog v6.0: https://portal.enx.com/en-us/TISAX/downloads/ +- VDA ISA 6.0 verpflichtend: https://vda-isa-berater.com/en/mandatory-vda-isa-catalog-version-6-0-for-all-those-who-order-the-tisax-assessment-now/ +- VDA Information Security: https://www.vda.de/en/topics/digitization/data/information-security diff --git a/docs/STAND-dev-branch.md b/docs/STAND-dev-branch.md new file mode 100644 index 0000000..98d4440 --- /dev/null +++ b/docs/STAND-dev-branch.md @@ -0,0 +1,404 @@ +# Entwicklungsstand `dev` — Konsolidierte Übergabe (PM + neue Entwickler) + +> Stand: 2026-07-30 · Branch **`dev`** · **Sync-Hinweis:** lokal **deutlich vor `origin/dev`** (`origin/dev` = `9b479ab`); enthält u. a. Prod-Deployment-Vorbereitung, Wizard-Kickoff + Story A1-1 und diese Doku. `dev` ist auf **`origin` (git.certvia.de)** und **`local-gitea` (intern)** gepusht. Vor dem nächsten Push zuerst `git fetch` und prüfen, ob niemand weitere Commits hat. **Alle Feature-Branches** (Dev A: A1–A8; Dev B: F1–F4, B1–B7 inkl. Prüfziel-Follow-up) sowie **Certvia-Branding**, der **Wizard-Parallelisierungs-Fix** und zuletzt das **Security-Härtungspaket P1/P2/P3 (F-01…F-20, u. a. RLS scharf F-04, moduleGuard-DB-Authz F-06, MFA-Replay, Container-/Supply-Chain-Härtung F-11/F-18)** sowie **SEC1 (Mailversand/Queue)**, **SEC2 (Auth-Self-Service: Passwort-Reset/-Wechsel/E-Mail-Änderung, Session-Invalidierung, Rate-Limit)** und zuletzt die **TISAX-Umstrukturierung (M0–M4: Fundament, Strukturanalyse, Cockpit mit RACI/Evidence, Audit-Wizard, TISAX-Tasks, Wizard-Neustruktur; v3: Prozesshaus + geführtes BIA je Prozess)** sowie **SEC3/SEC4 (MFA pro Mandant erzwingen, WebAuthn/Passkeys, TOTP-Verschlüsselung at rest, Plattform-Admin-Verwaltung)** sind per DevOps-Integration additiv nach `dev` konsolidiert (Gate grün); noch offene Feature-Branches rebasen auf `dev`. **Deployment-Pflichtschritte** aus dem Security-Paket siehe §1a (F-04 RLS scharfschalten, F-06×F-10 `scripts/sync-role-permissions.ts` nach `migrate`). **SEC1/SEC2 fürs Deployment:** eigener **Mail-Worker-Service** (`npm run worker:mail` = `scripts/mail-worker.ts`) nötig, echte **SMTP-Variablen** setzen, und die Queue nutzt **Redis** (`REDIS_URL` mit Passwort, BullMQ/ioredis) — der Worker fehlt noch in `docker-compose.coolify.yml`. · Basis-Doku: `docs/HANDOVER-DEV.md`, `docs/HANDOVER-PM.md`, `docs/SPEC.md` +> Zweck: Ein Dokument, das den kompletten Stand der Weiterentwicklung auf `dev` zusammenfasst — fachlich (für PM) und technisch (für einen neuen Entwickler). `dev` ist noch **nicht** nach `main` gemergt. + +> **Neu (2026-08-07):** `feature/settings-roles-platform-ui` integriert (Einstellungen umstrukturiert: Risikokriterien/Rollen als Menü-Karten + Link zur Plattform-Administration; neue Route `/settings/risk-criteria`). Zusätzlich **Audit-Trail einsehbar je Mandant**: wiederverwendbares server-gerendertes Popup (`src/components/audit-trail.tsx`, Muster wie die übrigen Popups über `?audit=1`) an **zwei** Stellen — Mandanten-Einstellungen `/settings` (eigener Mandant, TENANT_MODELS/RLS-gefiltert) und Plattform-Konsole `/admin/[id]` (Superadmin, cross-tenant über Owner-Client auf den Mandanten gefiltert). **Keine neue Migration.** Gate grün (tsc/lint/build + 17/17 Tests), Popup im Browser verifiziert. +> +> **Fix (2026-08-07):** `dev-fix-platform-admin` integriert — **Proxy-Gate für Plattform-Routen** (`src/proxy.ts`): `/platform/login` + `/api/platform-auth` sind jetzt public, und `/admin`, `/admins`, `/profile`, `/platform` gaten aufs Plattform-Session-Cookie und leiten anonyme Besucher auf **`/platform/login`** statt fälschlich auf die Mandanten-Login-Maske. Plus klarerer Modul-Toggle in `/admin/[id]` (Status-Pill + eigener „Aktivieren/Deaktivieren"-Button). Verifiziert: `/admin|/admins|/profile` → 307 `/platform/login`, `/dashboard` weiterhin → `/login`. Gate grün (17/17). +> +> **Fix (2026-08-07, 2):** Plattform-Auth bekommt **eigene Cookie-Namen für ALLE** Auth.js-Cookies, nicht nur `sessionToken` (`src/server/platform-auth.ts`): auch `csrfToken` (`__Host-platform-authjs.csrf-token`) und `callbackUrl` (`platform-authjs.callback-url`). Grund: zwei Auth.js-Instanzen auf derselben Domain teilten sich die Default-Cookies `authjs.csrf-token`/`authjs.callback-url`; da ein Nutzer zugleich Mandanten- und Plattform-Konto sein kann, überschrieb die zuletzt aktive Instanz das gemeinsame CSRF-Cookie → CSRF-Validierung der Plattform-Instanz schlug fehl (Sign-out warf, CSRF-POSTs/Session-Erneuerung landeten auf der Login-Maske). Getrennte Cookie-Namen isolieren beide Auth-Domänen vollständig. Gate grün (17/17). +> +> **Fix (2026-08-07, 3):** Plattform-Cookie-`secure`/Prefix folgt jetzt dem **AUTH_URL-Protokoll** (`https:`) statt `NODE_ENV` (`src/server/platform-auth.ts`, `PLATFORM_SECURE_COOKIES`), exakt wie Auth.js es für die Mandanten-Instanz tut (`useSecureCookies ?? url.protocol === "https:"`). Grund: im Container ist `NODE_ENV=production`, der interne Testserver wird aber ggf. über **http** bedient (AUTH_URL=http bzw. fehlendes `X-Forwarded-Proto`); ein hart auf `__Secure-`/`__Host-`/`secure` gesetztes Cookie wird vom Browser über http verworfen → Plattform-Session bleibt leer (jede Aktion → Login-Maske, Logout wirft), während die Mandanten-Session weiterläuft. **Betriebshinweis:** In Prod `AUTH_URL=https://…` setzen (dann greifen wieder secure-Cookies + `__Host-`/`__Secure-`-Prefixe). Gate grün (17/17). +> +> **Identity/Mandanten (Option C), WS0 (Fundament) — 2026-08-11:** globales `Identity`-Modell (kein `tenant_id`, **nicht** in `TENANT_MODELS`, keine RLS) + `User.identityId`; Migration `identity_foundation`; Reseed auf Identity+Membership inkl. 2. Mandant `demo2` + Multi-Membership-Fixture `multi@demo.example`. **Expand/Contract** (User-Auth-Felder bleiben vorerst Legacy; Contract-Migration droppt sie am Ende von WS1–WS4). Neuer Test `scripts/test-identity-schema.ts`. Grundlage/Fahrplan: `docs/FEINDESIGN-identity-mandanten.md`, `docs/KONZEPT-identity-mandanten.md`, `docs/UEBERGABE-identity-mandanten.md`, `docs/PROMPT-uebergabe-identity-mandanten.md`. Nächste Schritte: WS1 (Login gegen Identity, Two-Step + MFA-pending) → WS2 (`/select-tenant`), parallel WS3/WS4/WS6; Abschluss = Contract-Migration. +> +> **Identity/Mandanten (Option C), WS1/WS3/WS4/WS6 — 2026-08-11** (`feature/identity-auth-core` → `dev`, `--no-ff`, Gate grün: tsc/lint/build + **21/21** Tests; **noch nicht auf die Remotes gepusht**): +> - **WS1 Auth-Kern:** `auth.ts` authentifiziert gegen die globale `Identity` (Passwort/MFA/Lockout an der Identity); Mitgliedschaften werden geladen, der aktive Mandant per Organisations-Slug oder Single-Membership gewählt (mehrere **ohne** Slug ⇒ noch kein Login → `/select-tenant` = WS2). Login-Kern als `authorizeTenantCredentials()` exportiert. Session/JWT (`next-auth.d.ts`) neu: `identityId`/`activeMembershipId`/`memberships[]` (optional, da Plattform-Auth dieselben Typen nutzt); `tenantId` = aktiver Mandant → **356 dbForTenant-Call-Sites unverändert**. Test `scripts/test-identity-login.ts`. +> - **WS4 Passwort/MFA an Identity:** Passwortwechsel, MFA-Enroll/-Disable, Recovery-Codes und der **Session-Kill-Switch** (`sessionsValidAfter`) gehören der Identity (`account.ts`, `account/page.tsx`, `sessions.ts`). Guards (`action-guard.ts`, `(app)/layout.tsx`, `change-password`, `enroll-mfa`) lesen `mustChangePassword`/`sessionsValidAfter`/`mfaEnrolledAt` + globalen `identity.status` aus der Identity; Membership-Status/Rechte weiter aus `User`. Reset-Kette (`auth-recovery`/`auth-selfservice`/`auth-token`) auf `PrincipalType "identity"`. **Mandanten-Admin-Passwort-Reset entfernt** (goldene Regel 5). **E-Mail-Änderung für Mandanten-Konten deaktiviert = Phase 2.** Test `scripts/test-identity-account.ts`. **Abgetrennt (offen): WS4b WebAuthn→Identity** (Schema-Migration + `TENANT_MODELS` + `webauthn.ts`; Passkey-Login läuft bis dahin mandantengebunden). +> - **WS3 Einladungs-Lifecycle:** Nutzeranlage **nur per Einladung** (goldene Regel 4) — `TokenType "invitation"` (7 Tage) + neue öffentliche Seite `/invite` + `redeemInvitation`. `createTenantUser`/`createUser`/`inviteFunctionHolder` ohne pwMode „set"; **bekannte Identity → nur Mitgliedschaft ergänzen** (kein Passwort-Reset), unbekannt → Identity + Einladung; **neutrale Rückmeldung** (kein Cross-Tenant-Leak). `user-forms.tsx` = reines Einladungsformular. Test `scripts/test-invitation.ts`. +> - **WS6 Seed/Provision/Bootstrap:** bereits durch WS0 abgedeckt (`provisionTenant`/`seed.ts` Identity-fähig, `sync-role-permissions.ts` orthogonal) — kein Netto-neuer Code. +> - **Keine neue Migration** (WS1/WS3/WS4/WS6 sind code-only; das WS0-Schema trägt). +> +> **Identity/Mandanten (Option C) — WS2/WS4b/WS5 + Contract, UMBAU KOMPLETT — 2026-08-11** (`feature/identity-tenant-context` → `dev`, `--no-ff`, Gate grün: tsc/lint/build + **23/23**; **noch nicht gepusht**): +> - **WS2 Mandantenkontext:** Multi-Membership-Login ohne Organisations-Slug ergibt eine Session OHNE aktiven Mandanten → `(app)/layout` leitet auf **`/select-tenant`**. Wechsel server-autoritativ über **`setActiveTenant`** (`actions/tenant-switch.ts`, `unstable_update` + async jwt-`update`-Trigger → `resolveActiveMembership`: Rechte je Wechsel NEU aufgelöst). **Sidebar-`TenantSwitcher`** (nur bei >1 Mitgliedschaft). **Browser-verifiziert:** Wechsel demo↔demo2 inkl. Mandantenisolation (demo: 9 Assets, demo2: 0). Test `scripts/test-tenant-switch.ts`. +> - **WS4b WebAuthn→Identity:** Passkeys sind identitätsgebunden (Migration `20260811140000_webauthn_identity`: `webauthn_credentials` verliert `tenant_id`/RLS, verweist auf `identities`); `WebAuthnCredential` **raus aus `TENANT_MODELS`**. Passkey-Login/-Verwaltung über `identityId`. +> - **Contract-Migration** (`20260811150000_contract_user_auth_columns`): die 10 ungenutzten `User`-Auth-Spalten entfernt (`password_hash, must_change_password, failed_logins, locked_until, mfa_secret, mfa_enrolled_at, recovery_codes, last_totp_step, sessions_valid_after, is_platform_admin`) → **`User` = reine Mitgliedschaft** (`tenantId, identityId, email, name, status`). Expand/Contract abgeschlossen. DROP COLUMN → kein Reset. +> - **WS5 Two-Step-Login (Entscheidung A):** `/login` Schritt 1 (E-Mail+Passwort) → bei aktiver MFA kurzlebiger, signierter, einzweckiger `mfa_pending`-Cookie (KEINE Session) → **`/login/mfa`** Schritt 2 → `login-ticket`-Provider prägt die Session. Bausteine `verifyIdentityPassword`/`verifyIdentityMfa`/`finalizeIdentityLogin` (kein Passwort-Orakel, Lockout wie beim vollen Login). `src/server/login-ticket.ts` (HMAC). Runtime-verifiziert. Test `scripts/test-two-step-login.ts`. +> - **Damit ist der Umbau „Zentrale Identität mit Mandanten-Mitgliedschaften" vollständig** (alle 5 goldenen Regeln + Entscheidung A). Zwei neue Migrationen. **Offen: nur der Push auf beide Remotes** (origin + local-gitea) — bewusst zurückgehalten. Phase-2 (per-Mandant Step-up, E-Mail-Änderung als Identity-Op, PlatformAdmin-Konsolidierung) bleibt ausgeklammert. +> +> **Richtlinien-Vorlagen Plattform-Editor + EN-Paket — 2026-08-11:** `dev-fix-platform-admin` integriert — globale Vorlagen-Modelle + Migration `policy_templates`, Plattform-Editor (Entwurf/Veröffentlichen, Editoren für Anforderungen/Variablen), **Sprachwahl je Mandant** (`setTenantLocale`) und das **komplette EN-Übersetzungspaket** der Richtlinien-Vorlagen (Leitlinie, R01–R14, VA-01–VA-20, D01/P01, Baseline/Nachweisregister). Mandanten-Import liest die veröffentlichte DB-Version. +> +> **Härtung Argon2id — 2026-08-11:** Passwort-Hash-Parameter fixiert/dokumentiert (`src/server/password.ts`, `ARGON2_OPTIONS`: m=19456 KiB, t=2, p=1, outputLen=32; Argon2id = Lib-Default). Salt automatisch pro Hash (PHC-String), **kein** Pepper (dokumentiert). Nur neue Hashes betroffen. +> +> **Härtung Phase 2–3 (Ops-Doku) — 2026-08-11** (Lane `lane-haertung-ops`, **nur Markdown, kein App-Code/Migration, noch nicht nach `dev` gemergt**): **Phase 1 (Passwort-Pepper) ist erledigt** (Argon2-`secret`, zentral, in `dev`) — unverändert. Phasen 2–3 liegen jetzt als **Ops-Runbook** vor: `docs/DEPLOY-PROD-CONTABO.md` um **Host-Encryption at-rest** (LUKS/dm-crypt fürs Daten-Volume `pgdata`+MinIO, Boot-Unlock-Verfahren A/B, Passphrase im Passwortmanager) und **verschlüsselte Backups** (pgBackRest `aes-256-cbc` + `age` je Umgebung + restic für MinIO, Coolify-Cron/Retention/Restore-Test, Bezug zur App-Backup-Engine `BACKUP_ENC_KEY`/§9) ergänzt; neues **`docs/SECRETS-REGISTER.md`** (Ownership + Rotationsregel je Umgebung für `AUTH_SECRET`/`MFA_ENC_KEY`/`PASSWORD_PEPPER`/`BACKUP_ENC_KEY`/pgBackRest-Key/`age`-Keypair; `PASSWORD_PEPPER`+`MFA_ENC_KEY` als **nicht rotierbar** = Reset markiert). **Restore-Kohärenz-Regel** prominent in beiden Docs: Umgebungs-Secrets stehen nicht im Artefakt → Restore in fremde Umgebung bricht Passwort-/MFA-Prüfung bzw. Entschlüsselung. **DB-TLS (`sslmode`) + Vault/KMS bleiben Phase 2** (offen). Gate: nur `.md`, tsc/lint unberührt. +> +> **Merge-Zyklus 2026-08-11:** WS0 + Richtlinien/EN-Lane + Argon2 zusammen nach `dev` konsolidiert. Konflikt nur in `schema.prisma` (User-Relationsblock → Union mit `identity`) + `provision.ts` (auto-merge: Identity-Upsert **und** Policy-Variablen). DB neu gebaut (`migrate reset`, **52 Migrationen**, beide neuen koexistieren) + Seed. Gate grün: tsc/lint/build + **18/18 Tests**. +> +> **Konfigurierbarer Backup-Zielspeicher — 2026-08-17** (`lane-backup-target` → `dev`, `--no-ff`): Backup-/DSGVO-Zielspeicher jetzt **im Betreiber-Portal wählbar** (`/admin/backup`, Full-Admin + MFA-Step-up) — **Lokal** (persistentes Volume) oder **S3/MinIO**. `PlatformSetting` erweitert (`backupTarget`, `backupLocalDir`, `backupS3*`, `backupS3SecretKeyEnc` **verschlüsselt at-rest**), Migration `backup_target_config` (additiv). Statisches `backupStore` → **`getBackupStore()`** mit Präzedenz **DB → Env (`S3_*`/`BACKUP_LOCAL_DIR`) → lokaler Default `.backups`**, fail-secure bei unvollständiger S3-Config; alle Call-Sites umgestellt. **Persistentes `backups`-Volume** (app + backup-worker, `/app/.backups`) — Lokal überlebt Redeploys. Neuer Test `scripts/test-backup-target.ts`. Gate grün (tsc/lint/build + **28/28**), `/admin/backup` im Browser klickgeprüft (Lokal↔S3, Secret-Feld „nie Klartext"). Konzept/Prompt: `docs/KONZEPT-backup-target.md`, `docs/PROMPT-lane-backup-target.md`. +> +> **Modul „Vorfälle" (Incident-Management) IM-A — 2026-08-17** (`lane-incidents-a` → `dev`, vom Team): Fundament + Kern-Lifecycle/UI (Migration `incidents`, `src/app/(app)/incidents/*`, `src/server/actions/incidents.ts`, `docs/KONZEPT-incidents.md`, Test `scripts/test-incidents.ts`). IM-B (Meldefristen/Notifications) noch **in Arbeit** (eigener Branch `lane-incidents-b`). +> +> **Direkt-Download der Sicherung + S3-Bucket-Selbstheilung — 2026-08-17** (`lane-backup-download` @ `fe13a84` → `dev`, `--no-ff`): Neue Route `/api/platform/backup/download` (Full-Admin) — `exportTenant(persist:false)` streamt die verschlüsselte `.cvb` **inline in den Browser**, **ohne Worker/Redis/S3** („Sicherung herunterladen"-Button im Export-Popup). `S3BackupStore.ensureBucket()` legt einen fehlenden MinIO-Bucket beim ersten `put` **automatisch** an (behebt „The specified bucket does not exist"). Neuer Test `scripts/test-backup-download.ts`. Gate grün (tsc/lint/build + **30/30**). Merge über isoliertes Worktree (paralleler Team-Arbeitsbaum unberührt). +> +> **Modul „Vorfälle" IM-B/C/D (komplett) + Backup-Docker-Fix — 2026-08-18** (vom Team nach `dev` gemergt; von mir validiert + gepusht): **IM-B** (Meldefristen/Timer + Meldepflicht + Benachrichtigungen), **IM-C** (Verknüpfungen, Abschluss/Lessons-Learned, Export/Meldevorlagen), **IM-D** (E-Mail-to-Ticket Inbound + Provisionierung; Migration `incident_inbound_d`, Test `scripts/test-incident-inbound.ts`). Damit ist das Modul „Vorfälle" funktional komplett (IM-A…IM-D). **Docker-Fix:** `prisma/schema.prisma` wird jetzt auch in die `runner`-Stage kopiert — der Inline-Backup-Download läuft in der App (standalone), und die Backup-Topologie liest die Schema-Datei zur Laufzeit (Prisma 7 entfernt FK-Relationen aus dem Laufzeit-DMMF); sonst `ENOENT` → „Export fehlgeschlagen". Gate grün (tsc/lint/build + **33/33**). + +--- + +## 1. Executive Summary + +Auf `main` lag das Fundament (Auth/RBAC/Mandanten-Isolation, Assets/BIA, Risiko, Maßnahmen, Abhängigkeiten, Lieferanten, Richtlinien Phase 1/2a, Admin-Konsole Phase 1). Der Branch **`dev`** ergänzt fünf große Blöcke — alle mit `tsc`+`lint`+`build`, Modul-Guard-Check und (wo relevant) Browser-Verifikation abgeschlossen: + +1. **Produktionshärtung Phase 1** — API-seitige Modul-Durchsetzung, getrennter Superadmin-Store mit eigenem Login + MFA, nicht-destruktiver Richtlinien-Re-Import. +2. **Benutzer- & Rollenverwaltung** (ohne E-Mail-Flow) — Plattform-Admin verwaltet Nutzer je Mandant; Mandanten-Admin verwaltet Nutzer **und** Rollen intern; Force-Change-Passwort, Passwort-Policy, optionale MFA je Nutzer; Popup-UI wie bei Assets. +3. **Freigabe-Workflow + Aufgaben-Modul** — Richtlinien-Freigabe an eine konkrete Person, Bearbeitung im neuen Modul „Aufgaben", Dashboard-Kachel; plus zentralisierte Richtlinien-Governance (zentrale Variablen, Schutzbedarf, Coverage-Filter nach Assessment-Level). +4. **GAP-Report-Umsetzung (Richtlinien-Vorlagenpaket)** — WP1–WP4 + E2: sechs neue Verfahrensanweisungen (ISB-Volltexte), Inline-VA-Verlinkung, Rendering-Fix, generisches editierbares Register-Datenmodell. +5. **Register-Konsolidierung in Fachmodule** — vier generische Register in die Fachmodule überführt: **Software** und **Projekte** als eigene Asset-Typen (Popups wie bei Assets/Lieferanten), **kritische IT-Dienste** als schreibgeschützte Auto-Sicht aus BIA, REG-NET auf Referenzfeld reduziert; Richtlinien-Links zeigen jetzt auf die Module statt auf Register. +6. **Produktions-Deployment-Vorbereitung** (Commits `cc8d486`, `f368d8f`) — Prod-Bootstrap `scripts/bootstrap-admin.ts` (legt Erst-Superadmin im `platformAdmin`-Store + Mandant/Mandanten-Admin idempotent an, ersetzt in Prod den Demo-Seed; per `BOOTSTRAP_*`-Env im `migrate`-Job der `docker-compose.coolify.yml`); `.env.prod.example`; **Fonts selbst gehostet** (`next/font/local`, committete woff2 in `src/app/fonts` → reproduzierbarer Offline-Build, DSGVO); Runbook **`docs/DEPLOY-PROD-CONTABO.md`** (VPS/Coolify/Gitea, TLS `app.certvia.de`, Bootstrap, Backups, Go-Live-Checkliste). + +7. **Branding-Umstellung auf Certvia** — **in `dev` integriert (Gate grün)**: getrennte Token-Ebenen `--brand-*` (Logo/Print/Export) vs. `--ui-*` (Produktpalette, inhaltlich unverändert) mit `src/lib/brand.ts` als JS-Pendant; Certvia-Logo als Inline-SVG-Komponente (``), Favicon-/PWA-Icons + `site.webmanifest`, Metadaten/OG/i18n/TOTP-Issuer, gebrandete Auth-Seiten sowie **neue 404-/500-Seiten**, Druck-/Dokument-CD (`@media print` + `src/lib/document-brand.ts`) als Andockpunkt für den offenen DOCX/PDF-Export, brandfähige E-Mail-Basis (`src/lib/email-brand.ts`), Mandanten-Branding-Default (`resolveTenantBranding`). **GEFIM bleibt Dachmarke** („Ein Produkt von GEFIM"). Reines Branding, keine Funktionsänderung — Ausnahme: der Route-Gate-Matcher in `src/proxy.ts` musste `.webmanifest` freigeben, sonst lieferte `/site.webmanifest` die Login-HTML. Details: **`docs/BRANDING-CERTVIA.md`**. + +**In Arbeit (parallele Entwicklung, 2-Lane Dev A × Dev B):** **Onboarding-Wizard** (`docs/wizard-uebergabe/`). **Beide Lanes bis hierher in `dev` konsolidiert** (inkl. Dev-B **B4**, per Fast-Forward integriert)**:** +- **Dev A:** A1-1 — Wizard-Shell: Modul `onboarding`, Step-Registry (`registerStep`, Keys 1–9, `guard` kann Schritte ausblenden), resumierbarer Fortschritt (`OnboardingProgress`). **F2** — generalisiertes `ObjectReviewStatus` (5 Zustände inkl. `zurueckgewiesen`) als wiederverwendbares Review-Enum; RBAC-Recht `validate_objects` + klonbare Rolle `external_validator`; Wizard-State-Machine mit Rechte-Trennung: Bearbeiter (`onboarding:use`) advance/rework/reset, Validator (`validate_objects`) validieren/zurückweisen (mit Begründung). „Weiter"-Gate: nur `validiert` zählt. Migration `object_review_status`. **A1-2** — Dashboard-Kachel „Onboarding-Fortschritt" (Anteil validierter Schritte + nächster offener Schritt, verlinkt in den Wizard). **A2-1** — Assessment-Level (AL2/AL3) als **einzige** Quelle des Schutzbedarfs: `protectionFlags(level)` (`src/server/assessment-level.ts`) leitet `FLAG_HIGH_PROTECTION`/`FLAG_VERY_HIGH_PROTECTION` zentral ab (Wizard/Provisioning seeden daraus, **nicht** mehr aus dem Fragebogen); Schutzbedarf-Frage `Q-FEAT-01` + Regeln `feat01-*` entfernt. **A2-2** — Scope-Objekt `WizardScope` + Filter-Engine (`src/lib/scope-filter.ts`: `activeRequirements`/`scopeSummary`, client-safe): filtert die Anforderungen nach AL-Baseline, `FLAG_INCLUDE_SHOULD` und Prüfzielen; Grunddaten `seed/scoping/c1-scope.json` (412 Anforderungen, generiert via `scripts/build-c1-scope.ts`); Action `saveScope` (`moduleGuard('onboarding')`) am Wizard-Schritt „scoping"; Migration `wizard_scope`; Tests `scripts/test-scope-filter.ts` (grün). **A3-1** — Validierungs-Workflow generalisiert: wiederverwendbares generisches Objekt-Review (`src/server/object-review.ts`, `src/lib/object-review.ts`, `src/components/object-review.tsx`) über Objekttypen hinweg (u. a. Risiken), an Risk-/Task-Actions angebunden. **A4** — ISMS-Rollen als Wizard-Schritt 3 „roles" inkl. Funktionstrennung FT-01…06 (`src/lib/ft-rules.ts`, Tests `scripts/test-ft-rules.ts`), ISB-Bestellung (`src/lib/isb-bestellung.ts`) und Rollen-Logik (`src/server/roles.ts`). **A5-1** — Asset-Schritt (Wizard-Schritt 5) auf dem Bestandsmodul (`steps/assets/step.tsx`). **A7** — **Control-Assessment** (Wizard-Schritt 7): Reifegrad-Engine R0–R3 + Zielreifegrad (`src/lib/maturity.ts`, Tests `scripts/test-maturity.ts`), Modell `ControlAssessment` (Migration `control_assessments`, RLS, in `TENANT_MODELS`) mit Belegstatus/Reifegrad-Bestätigung/Gap-Aufgaben; SoA-Kontext (`src/server/soa-context.ts`, `actions/soa.ts`), Control-Grunddaten `seed/scoping/c5-controls.json`. **A6** — **Standard-Risikokatalog (C4)**: globaler Katalog `RiskCatalogEntry` (Migration `risk_catalog`, kein RLS) + Import/Übernahme (`prisma/import-risks.ts`, `/risks/catalog`); A6-2 Standardmaßnahme→Aufgabe und **Restrisiko-Akzeptanz** (Migration `risk_acceptance`: Felder `accepted_at/by/rationale` an `risks`, VA-09). **A8** — **Gap-Konsolidierung** (Wizard-Schritt 8): Aggregations-/Priorisierungs-Engine (`src/lib/gap-consolidation.ts`: Dedup, Priorisierung, Quick-Wins), Task-Abgleich + Kontext (`src/server/gap-context.ts`, `src/server/actions/gap.ts`), Tests `scripts/test-gap-consolidation.ts` (keine neue Migration/Modell). +- **Dev B:** F1 (Task-Objekt um Wizard-Felder `type/owner/dueDate/priority/status/resources/origin/links` erweitert, Migration `tasks_wizard_fields`), B1 (Auto-Generierung von Aufgaben-Vorschlägen aus Triggern, C2 §8; `src/lib/task-triggers.ts`, `src/lib/tasks.ts`), F4 (Wizard-Flags in `variables.schema.json`: `FLAG_PROTOTYPE_PROTECTION`, `FLAG_ISB_EXTERNAL`, `FLAG_ISB_INTERNAL`; `_verify.py` = OK). **F3+B2** — Regel-/Mapping-Engine: deklarative DSL (`src/lib/rules/dsl.ts`), Auswerter (`engine.ts`, `evaluateCondition`) und C2-§5-Regelwerk (`feature-rules.ts`: Feature-Flags, Schutzbedarf-Ableitung, Control-Scope, Risiko-/Aufgaben-Trigger); Tests `scripts/test-rules.ts` (18 Fälle, grün). **B3** — Fragebogen als Wizard-Schritt 2 „context": Frage-Katalog A–F (`src/lib/onboarding/questions.ts`), Fakten-Ableitung (`facts.ts`, `deriveContext` über die Regel-Engine), Schritt-Komponente + `saveFacts`-Action (`onboarding-facts.ts`), Modell `WizardFact` (Migration `wizard_facts`, RLS, in `TENANT_MODELS`); echte Schritte via Side-Effect-Import `register-steps.ts` in die Registry eingeklinkt (überschreibt Platzhalter). Der Fragebogen schreibt **nur** Fakten/Flags, nie die gesperrten Zentralvariablen. **B4** (Richtlinien-Import/Upload) — **in `dev` integriert (Fast-Forward), Gate grün**: **B4-1** nicht-destruktiver Vorlagen-Import bei Aktivierung des Richtlinien-Moduls + Self-Service-Button (`/policies`, Report-Banner) und Admin-Button (`src/server/actions/policy-package.ts`, Trigger in `toggleTenantModule`); **B4-2** „Eigene Richtlinie hochladen" (`/policies/upload`, `policy-upload.ts`) mit Pflicht-Control-Zuordnung + gekapseltem Storage-Adapter-Stub (`src/server/storage/adapter.ts`, echtes Backend = Epic S1) → EIGENES-Dokument (`EIG-*`) + PolicyRequirement-Zeilen (Coverage/Nachweislage); **B4-3** neue Vorlagen `P01_Prototypenschutz` + `VA-20` (Kap. 8.x) und `D01_Datenschutz` (9.x) + 5 `mapping.json`-Anforderungen (condition-gated per Prüfziel-Flag), `_verify.py` = OK. **Keine neue Migration** (nur String-Status/Seed-Content). **B5** (Umsetzungshinweise C6) — **in `dev` integriert, Gate grün**: **B5-1** Datenmodell `ImplementationHint` (Migration `implementation_hints`; **globaler C6-Katalog**, identisch je Mandant → kein `tenantId`/RLS) + C6-Import (~397 Hinweis-Blöcke via `prisma/import-hints.ts` / `scripts/import-c6-hints.ts`); **B5-2** kontextsensitives Umsetzungshinweis-Panel (`/policies/hints`, `src/server/actions/hints.ts`), aus `/policies` verlinkt. **Prüfziele Single Source** (Follow-up zu A2): der context-Step seedet die Prüfziele aus `WizardScope` statt aus einer zweiten Quelle (Doppelquelle behoben; `feature-rules.ts`/`facts.ts`/`questions.ts`, `test-rules.ts` angepasst). **B6** — Vorlagenpaket-**Versionierung** + kontrollierte **Diff-Übernahme**: Modell `PolicyPackageState` (Migration `policy_package_state`, RLS, in `TENANT_MODELS`) hält je Mandant Paket-Version/-Stand; `stampPackageState` (in `prisma/import-policies.ts`) beim Import; Updates-Ansicht `/policies/updates` zeigt/übernimmt Änderungen kontrolliert. **B7-1** — Assessment-**Readiness-Dashboard** als Wizard-Schritt 9 „readiness" (`src/lib/readiness.ts`, Tests `scripts/test-readiness.ts`) mit Interpretationstexten (C9 §1/§2). **B7-2** — **VDA-ISA-Katalog-Export** (CSV) + **Management-Zusammenfassung** (C9 §3/§4): Export-Route `onboarding/export/route.ts`, Export-Engine `src/lib/export/vda-isa.ts` + `src/server/export-context.ts`, Zusammenfassungs-Seite `onboarding/summary`, Tests `scripts/test-vda-isa.ts`. Damit ist **B7 vollständig** (keine neue Migration). **Wizard-Schritte 4 + 6 (echte Komponenten)** — Richtlinien-Schritt „policies" (Schritt 4, Guard: nur bei aktivem Richtlinien-Modul) und Risiken-Schritt „risks" (Schritt 6, Guard: nur bei aktivem Risiko-Modul) zeigen jetzt den echten Modul-Status statt Platzhalter (`steps/policies/step.tsx`, `steps/risks/step.tsx`, `src/server/actions/onboarding-steps.ts`) — keine Doppel-Datenhaltung. Damit sind **alle Wizard-Schritte 1–9 echte Komponenten**. +- **Offen:** **Keine offenen Feature-Branches mehr** — alle bestehenden Lanes in `dev` konsolidiert (Dev A: A1–A8; Dev B: F1/B1/F4/F3+B2/B3/B4/B5/B6/B7 + Prüfziel-Follow-up). Nächste geplante Stories siehe §6. + +**Migrationen (31 neu, laufen beim Deploy automatisch über den Init-Container):** +`platform_admins` · `policy_lifecycle_archived` · `user_mgmt_and_platform_settings` · `tasks` · `strip_tool_variable_articles` · `managed_registers` · `software_and_project_assets` · `onboarding_progress` · `tasks_wizard_fields` · `object_review_status` · `wizard_facts` · `wizard_scope` · `implementation_hints` · `policy_package_state` · `control_assessments` · `risk_catalog` · `risk_acceptance` · `task_description` · `control_implementations` · `login_lockout` · `mail_fundament` (SEC1) · `auth_tokens_sessions` (SEC2) · `tisax_m0_foundation` · `tisax_m1_m4_consolidated` · `tisax_rekey_onboarding_steps` · `tisax_v3_process_fields` · `tisax_v4_catalog_parent` · `tisax_v5_audit` · `tisax_v7_policy_domain` · `webauthn_credentials` (SEC3) · `platform_admin_role` (SEC4) + +--- + +## 1a. Sicherheitspaket P1/P2 (Branch `dev-security-p1`, Stand 2026-07-30) + +Nach einem externen Secure-Code-Review (AEGIS-SAST, 21 Findings) wurde ein Härtungspaket umgesetzt: **alle P1 (2) und P2 (5) sowie mehrere P3** sind behoben. Das Paket liegt auf **`dev-security-p1`** (von `dev` abgezweigt, Gate grün, noch **nicht** nach `dev` gemergt). Parallelisiert in drei konfliktfreien Lanes plus Vorlauf, danach additiv integriert. + +| Finding | Priorität | Behebung | Kern-Dateien | +|---|---|---|---| +| **F-01** Auth.js „fail open" + Next.js-CVEs | P1 | `next-auth`→`5.0.0-beta.32` (`@auth/core` 0.41.3), `next`→`16.2.12`; Guards **positiv** statt existenzbasiert; **Fail-Secure-Startprüfung** `assertSecureEnv()` (lazy/memoisiert, build-safe) | `package.json`, `src/server/env.ts`, `auth.ts`, `platform-auth.ts` | +| **F-02** Cross-Tenant-Leck bei `findUnique`+`select` | P1 | Tenant-Guard **fail-closed**: skalare `where`→`findFirst` mit `tenantId`-Vorfilter (verhindert statt erkennt), Compound-Unique→`tenantId`-Injektion + harter Abbruch; drei Aufrufstellen zusätzlich explizit gefiltert; Regressionstest | `src/server/db.ts`, `actions/risks.ts`, `actions/risk-catalog.ts`, `scripts/test-tenant-isolation.ts` | +| **F-03** Stored XSS im Richtlinien-Rendering | P2 | `renderPolicyHtml` sanitisiert `marked`-Output gegen strikte Allowlist (`sanitize-html`); Variablenwerte + Upload-Titel HTML-kodiert vor `noEscape`-Handlebars | `src/lib/policy-render.ts`, `actions/policy-upload.ts` | +| **F-05** Kein Brute-Force-Schutz Mandanten-Login | P2 | Kontosperre (5/15 min) + `denied`-Audit analog Plattform-Login; Enumeration via Dummy-Hash konstanter Laufzeit; DoS-Ausnahme letzter aktiver Admin | `auth.ts`, Migration `login_lockout` (`User.failedLogins/lockedUntil`) | +| **F-07** Keine Security-Header/CSP | P2 | CSP + HSTS + `nosniff` + `X-Frame-Options: DENY` + Referrer-/Permissions-Policy; `unsafe-eval`/`ws:` nur im Dev | `next.config.ts` | +| **F-08** Kritische Kontoänderung ohne Re-Auth | P2/P3 | Passwortwechsel verlangt aktuelles Passwort (+ TOTP bei aktiver MFA); MFA-Deaktivierung erfordert TOTP-Code; Ausnahme nur beim erzwungenen Erstwechsel | `actions/account.ts`, `actions/platform.ts` | +| **F-09** 30-Tage-Sessions | P3 | `maxAge` 8 h (Mandant) / 2 h (Plattform) + `updateAge` | `auth.ts`, `platform-auth.ts` | +| **F-12** Weitere verwundbare Abhängigkeiten | P3 | `overrides` für `postcss`/`sharp`/`valibot`; **Produktionsbaum (`--omit=dev`): 0 kritisch / 0 hoch** (vorher 2/5) | `package.json` | +| **F-15** Upload ohne Validierung | P3 | Größenlimit vor RAM-Read, Endungs-/MIME-Allowlist, Magic-Byte-Prüfung, kanonischer MIME statt `f.type` | `actions/policy-upload.ts` | +| **F-16** (Teil) Isolationsverletzung unsichtbar | P3 | Verletzungen als `[SECURITY]`-Log; zentrale Audit-Anbindung (`action:"denied"`) als Folge-TODO offen (Importzyklus `audit.ts`↔`db.ts`) | `src/server/db.ts` | +| **F-19** Unvalidiertes `callbackUrl` | P4 | Allowlist (nur eigene absolute Pfade), doppelt validiert | `src/app/login/page.tsx` | + +**Korrekturen am Bericht** (dessen Codevorschläge waren an drei Stellen falsch): `npm install next-auth@latest` hätte auf **v4** downgegradet (Major-Bruch) — korrekt ist `5.0.0-beta.32`. Der pauschale `findUnique`→`findFirst`-Umbau bricht an den Compound-Unique-Keys (`tenantId_key` etc.) → stattdessen Hybrid-Guard. Das RLS-Snippet aus F-04 funktioniert nicht (Kontext in falscher Transaktion) → F-04 bewusst herausgelöst. + +| **F-06** JWT-Sessions ohne Widerruf | P2 | ✅ **Branch `dev-security-f06-session-auth`** (auf `dev-security-f04-rls`): `moduleGuard` prüft Kontostatus, `mustChangePassword` und effektive Rechte je Mutation **autoritativ aus der DB** statt aus dem JWT → Deaktivierung/Rechteentzug wirkt sofort (vorher bis Token-Ablauf); `requirePlatformSession` prüft Plattform-Admin-Status. Test `test-action-guard-authz.ts` (4 Nachweise), Browser-Regression ok | `src/server/action-guard.ts`, `platform-auth.ts` | +| **F-04** RLS definiert, aber wirkungslos | P2 | ✅ **Separates Paket, Branch `dev-security-f04-rls`** (auf `dev-security-p1` aufgesetzt): env-gesteuert (`RLS_ENFORCED`). Zweite Verbindung als `isms_app` (`RLS_DATABASE_URL`, NOBYPASSRLS); `dbForTenant` setzt `app.tenant_id` transaktionslokal auf derselben Connection; Policies mit `USING`+`WITH CHECK` + `FORCE` auf allen **49** Tenant-Tabellen. Owner-Rolle (Superuser/BYPASSRLS) bleibt für Migrationen/Seed/Login und lokal unberührt → Default-Betrieb unverändert. Test `test-rls-enforcement.ts` (5 Nachweise) | `src/server/db.ts`, Migration `rls_enforce`, `docker-compose.coolify.yml`, `.env*.example`, `DEPLOY-PROD-CONTABO.md` | + +**Gate (kombinierter Stand A+B+C):** `tsc`=0 · `lint` sauber · `build` grün · `_verify.py`=OK · `test-tenant-isolation`=OK (15 Fälle) · Browser-Smoke (Login, Dashboard, Richtlinien-Register, CSP-Header, Guard-Redirect) verifiziert. **F-04 separat:** `tsc`/`lint`/`build` grün · `test-rls-enforcement`=OK (5/5, inkl. Nachweis „Owner-Betrieb heil unter FORCE") · Owner-Pfad-Smoke verifiziert. + +### P3/P4-Paket (Branch `dev-security-p3`, auf `dev-security-f06-session-auth`, Stand 2026-07-30) + +Vier dateidisjunkte Lanes, additiv gemergt, kombiniertes Gate grün. **Nur die MFA-Lane migriert.** + +| Finding | Prio | Behebung | Kern-Dateien | +|---|---|---|---| +| **F-10** Aufgaben-Modul ohne Rechteprüfung | P3 | Neues Recht `task:write`; `guard("task:write")` in `createTask`/`proposeTasksFromTriggers`/`claimTask`/`updateTask`; `CreateTaskInput` per Zod (Längen-/Größenlimits); `owner`/`assignee` gegen aktiven Mandanten-Nutzer geprüft | `rbac.ts`, `actions/tasks.ts` | +| **F-13** Privilege Escalation über `role:manage` | P3 | **Pragmatische Variante** (Entscheidung): Delegation erlaubt (Admin darf fachliche/geklonte Rollen für andere anlegen), aber **Selbstzuweisung** höher privilegierter Rollen gesperrt → Selbst-Eskalation ausgeschlossen; volle Auditierung | `actions/tenant-users.ts` | +| **F-20** Schwache Passwort-Policy bei Provisionierung | P3 | `validatePassword(…, DEFAULT_PASSWORD_POLICY)` statt `min(8)` | `actions/admin.ts` | +| **F-16-zentral** Sicherheitsereignisse nur im Log | P3 | Importzyklus per Lazy-Import gelöst → Isolationsverletzung wird echter `denied`-Audit; Error-Boundary `withActionErrors` (generische Außenmeldung, volles internes Log) bereitgestellt | `db.ts`, neu `action-error.ts` | +| **F-17** Recovery-Codes SHA-256, TOTP-Replay | P3 | Recovery-Codes → Argon2id, Entropie 40→80 Bit (Alt-Codes per Kompatibilitätspfad bis Neuausstellung); TOTP-Replay-Schutz via `lastTotpStep` (User+PlatformAdmin) | `mfa.ts`, `auth.ts`, `platform-auth.ts`, `account.ts`, `platform.ts`, Migration `mfa_totp_replay` | +| **F-11** Supply Chain | P3 | `npm ci` (Base-Image → `node:22.14.0-slim`/glibc, npm 11 gepinnt), alle Images auf feste Tags/Digests, schlanke `migrate`-Stage, SBOM dokumentiert; lokaler `docker build` grün (386 MB) | `Dockerfile`, `docker-compose*.yml` | +| **F-18** Container-Härtung | P3/P4 | Redis-Passwort, internes Netz (`internal: true`), `no-new-privileges`/`cap_drop: ALL`/Ressourcenlimits, Dev-Compose auf `127.0.0.1` gebunden | `docker-compose*.yml`, `.env*.example` | +| **CI/Renovate** (Begleitmaßnahmen) | — | `.gitea/`+`.github/workflows/ci.yml` (tsc/lint/build + `npm audit --omit=dev --audit-level=high`-Gate), `renovate.json` (Auth-Updates manuell) | `.gitea/`, `.github/`, `renovate.json` | + +**Gate (kombiniert):** `tsc`=0 · `lint` · `build` · `_verify.py`=OK · 7 Sicherheitstests grün (`tenant-isolation`, `rls-enforcement`, `action-guard-authz`, `tenant-users-authz`, `mfa-hardening`, `action-error`) · Browser-Smoke (Task-Anlage F-10) verifiziert. + +> ✅ **Deployment-Schritt (F-06 × F-10) — automatisiert:** Da F-06 Rechte **DB-autoritativ** prüft, wirkt eine neue Permission (z. B. `task:write`) erst, wenn `scripts/sync-role-permissions.ts` gegen die Ziel-DB läuft (legt Permission + Rolle→Recht-Verknüpfung an; additiv, idempotent). Ein reiner Re-Login genügt NICHT. Das läuft jetzt **bei jedem Deploy automatisch im `migrate`-Init-Job** (`docker-compose.coolify.yml`, direkt nach `prisma migrate deploy`, über die Owner-`DATABASE_URL`) — deckt jede künftig neu eingeführte Permission ab. Betroffene Nutzer danach neu einloggen. Manuell nachziehen nur, falls ohne Redeploy nötig: `npx tsx scripts/sync-role-permissions.ts`. + +**Noch offen:** **F-14** (Demo-Seed-Härtung — auf Wunsch bewusst zurückgestellt), **F-21** (Monitoring/Log-Aggregation/Tamper-Schutz Audit-Trail — eigenes Betriebspaket). Damit sind **alle P1, alle P2 und die adressierten P3** behoben. Details: AEGIS-Bericht. + +**Aktivierung F-04 in Prod:** Rolle `isms_app` LOGIN+starkes Passwort geben, `RLS_DATABASE_URL` setzen, `RLS_ENFORCED=true` am `app`-Service; Migrations-/Owner-Rolle muss BYPASSRLS/Superuser sein. Anleitung in `docs/DEPLOY-PROD-CONTABO.md`. Lokal bewusst **aus**. + +--- + +## 2. Für das Projektmanagement — fachlicher Status + +### ✅ Neu fertig auf `dev` + +| Thema | Nutzen | Status | +|-------|--------|--------| +| **API-seitige Modul-Durchsetzung** | Deaktiviertes Modul sperrt jetzt auch Schreibzugriffe serverseitig (nicht nur Navigation); automatischer Vollständigkeitscheck als Build-Gate | ✅ | +| **Getrennter Superadmin-Login** | Betreiber-Zugang unter `/platform/login` mit eigenem Store, ohne Mandantenkontext; Kundenfachdaten für Superadmin gesperrt | ✅ | +| **MFA (optional)** | TOTP für Plattform-Admins **und** Mandanten-Nutzer freiwillig; Policy-Flag „MFA-Pflicht" kann Erzwingung wiederherstellen; Recovery-Codes | ✅ | +| **Benutzerverwaltung (Superadmin)** | Superadmin legt je Kunde Nutzer an (Initial-/Einmal-Passwort), weist Rollen zu, deaktiviert/reaktiviert, setzt Passwörter zurück | ✅ | +| **Benutzer- & Rollenverwaltung (Kunde)** | Mandanten-Admin verwaltet **intern** Nutzer und Rollen (eigene Rollen + granulare Rechte, Standardrollen klonbar); strikt mandantengetrennt; Lockout-Schutz | ✅ | +| **Nutzer-Onboarding ohne E-Mail** | Start mit Initialpasswort + erzwungenem Wechsel beim ersten Login; E-Mail-Einladung (Paket 4) später nahtlos ergänzbar | ✅ | +| **Popup-Bedienung** | Anlegen/Bearbeiten von Nutzern über Popups wie bei Assets; Tabelle nur Anzeige | ✅ | +| **Zuständigkeiten geklärt** | Superadmin steuert Kern-Einstellungen (Module, TISAX-Tiefe); Mandanten-Admin nur seinen Bereich (Stammdaten, Nutzer/Rollen) | ✅ | +| **Richtlinien-Governance zentral** | Zentrale Variablen (Unternehmensname, Rollen, Schutzbedarf) nur in Einstellungen pflegbar; Coverage-Matrix zeigt nur Controls des aktiven Assessment-Levels (AL2 ohne „sehr hoch") | ✅ | +| **Scoping & zentraler Schutzbedarf (A2)** | Anforderungs-Scope leitet sich zentral aus Assessment-Level (AL2/AL3), `FLAG_INCLUDE_SHOULD` und den Prüfzielen ab — nicht mehr aus dem Fragebogen; Schutzbedarf hat damit eine einzige, konsistente Quelle (AL → Flags). Scope-Filter (`scope-filter.ts`) + `c1-scope.json` (412 Anforderungen) | ✅ | +| **Umsetzungshinweise (B5)** | Kontextsensitive C6-Umsetzungshinweise (~397 Blöcke) zu den Controls, als eigenes Panel unter `/policies/hints` und aus den Richtlinien verlinkt — praktische Hilfestellung bei der Umsetzung | ✅ | +| **Validierungs-Workflow generalisiert (A3)** | Das Vier-Augen-/Review-Muster ist jetzt objekttyp-übergreifend nutzbar (nicht nur Aufgaben) — z. B. für Risiken | ✅ | +| **ISMS-Rollen & Funktionstrennung (A4)** | Wizard-Schritt „Rollen": ISMS-Rollen zuweisen, Funktionstrennungs-Regeln FT-01…06 prüfen (z. B. ISB ≠ IT-Leitung), ISB-Bestellung | ✅ | +| **Vorlagen-Versionierung & Diff (B6)** | Das Vorlagenpaket ist versioniert; Updates werden je Mandant kontrolliert per Diff-Ansicht (`/policies/updates`) übernommen statt blind überschrieben | ✅ | +| **Assessment-Readiness & Export (B7)** | Readiness-Dashboard (Reifegrad-Interpretation, C9) **plus** VDA-ISA-Katalog-Export (CSV) und Management-Zusammenfassung — Grundlage für Reporting/Abschluss | ✅ | +| **Wizard-Schritte Richtlinien & Risiken (B)** | Onboarding-Schritte 4 (Richtlinien) und 6 (Risiken) zeigen den echten Modul-Status statt Platzhaltern — der Wizard ist damit über alle 9 Schritte durchgängig | ✅ | +| **Umsetzungshinweise im Control-Schritt (#10)** | Je Control-Anforderung lassen sich die Umsetzungshinweise **dokumentieren, abhaken und in eine Aufgabe überführen**; der Umsetzungsstatus je Spiegelstrich fließt in den Reifegrad ein (`ControlImplementation`) | ✅ | +| **Aufgaben/Maßnahmen-Vereinheitlichung (7-9)** | Aufgaben und Maßnahmen im selben Bedien-Design (gemeinsamer Anlage-Dialog); Standardmaßnahmen aus dem Risikokatalog werden zu echten, verknüpften Maßnahmen; neue Rolle **`pm`** mit Voll-Sicht auf Aufgaben (`task:read_all`) | ✅ | +| **Wizard-UX-Feinschliff (#1/#3/#6)** | Interne Identifier aus den Wizard-Texten entfernt, Assets-Schritt gibt Rückmeldung beim „Aufgaben anlegen", Aufgaben-Sichtbarkeit als Pool-Popup | ✅ | +| **Asset-Schritt (A5)** | Wizard-Schritt 5 bindet das Bestands-/Asset-Modul ein — Assets werden im Onboarding erfasst statt separat | ✅ | +| **Control-Assessment & Reifegrad (A7)** | Wizard-Schritt 7: Controls bewerten (Belegstatus, Reifegrad R0–R3, Zielreifegrad); offene Punkte erzeugen automatisch Gap-Aufgaben | ✅ | +| **Standard-Risikokatalog (A6)** | Vorgefertigter Risikokatalog (C4) zum Übernehmen; Standardmaßnahmen erzeugen Aufgaben; dokumentierte **Restrisiko-Akzeptanz** (VA-09) | ✅ | +| **Gap-Konsolidierung (A8)** | Wizard-Schritt 8 bündelt alle offenen Punkte/Gaps aus den Schritten — dedupliziert, priorisiert (Quick-Wins) und gleicht sie mit Aufgaben ab | ✅ | +| **Freigabe-Workflow + Aufgaben** | Einreicher wählt Freigeber → Aufgabe; Freigeben/Ablehnen (mit Kommentar) im Modul „Aufgaben" (Vier-Augen); Dashboard-Kachel für offene Freigaben | ✅ | +| **Nicht-destruktiver Re-Import** | Richtlinien-Paket-Updates erhalten Status/Freigabe/Overrides/Variablenwerte; entfernte Einträge werden deaktiviert statt gelöscht; Änderungsreport | ✅ | +| **GAP-Report Richtlinien** | 6 neue Verfahrensanweisungen (VA-14..19), alle zuständigen VAs inline verlinkt, Rendering-Fehler behoben, verwaltete Register editierbar | ✅ | +| **Software-Verwaltung** | Software ist ein Asset (Typ SOFTWARE) und wird im Lieferantenbereich unter „Software" gepflegt (Popups wie IT-Services): Anbieter/Lieferant, Version/Patch-Stand, Freigabestatus, Freigeber, Review. Ersetzt die frühere „Software-Whitelist" | ✅ | +| **Projekte** | Projekte sind Assets (Typ PROJECT) im Assetinventar: bewertbar wie Assets (Kritikalität C/I/A), Risiken zuordenbar, IS-Klassifizierung, ISB-Einbindung, Projektstatus — Bedienung als Popup | ✅ | +| **Kritische IT-Dienste** | Schreibgeschützte Auto-Sicht (`/assets?view=critical`): leitet kritische Dienste automatisch aus Verfügbarkeit und BIA ab, mit RTO/RPO aus den verknüpften Prozessen und Abhängigkeiten — keine gepflegte Doppelliste mehr | ✅ | +| **Register-Konsolidierung** | Doppelte Register (externe IT-Dienste, Software-Whitelist, kritische Dienste, Projekte) entfernt und in die Fachmodule überführt; Richtlinien-Verweise zeigen jetzt auf die Module. REG-NET (Netzplan) auf ein Referenz-/Speicherort-Feld reduziert | ✅ | +| **Produktmarke Certvia** | Die Anwendung heißt und erscheint durchgängig als **Certvia** — Logo und Wortmarke, Tab-/App-Icon, Seitentitel, Anmelde- und Fehlerseiten, Druckansicht. GEFIM bleibt als Dachmarke sichtbar („Ein Produkt von GEFIM"). Ohne eigenes Mandanten-Logo zeigt jeder Kunde Certvia. Reine Design-Umstellung ohne Funktionsänderung | ✅ | +| **Wizard-Parallelisierung (Fix)** | Bearbeitung und Validierung im Onboarding-Wizard entkoppelt — Schritte können parallel bearbeitet werden, statt streng nacheinander; dazu `scripts/sync-role-permissions.ts` zum Nachziehen neuer Rechte für bestehende Mandanten | ✅ | + +### 🟥 Bewusst zurückgestellt / offen + +| Thema | Anmerkung | +|-------|-----------| +| **Paket 4 — SMTP + E-Mail-Einladungs-/Reset-Flow** | Auf Kundenwunsch später; Aktivierung läuft vorerst über Initial-/Einmal-Passwort, gekapselt für spätere Token-Aktivierung | +| **Netzplan-Datei-Upload (REG-NET)** | Datei-Upload-/Storage-Infrastruktur existiert noch nicht; REG-NET verweist vorerst per Feld auf den extern gepflegten Netzplan. Upload als eigenes Paket (Storage-Backend + Coolify-Volume) | +| **Tenant-weite MFA-Pflicht scharfschalten** | Flag `securityPolicy.mfaRequired` vorhanden + von „MFA deaktivieren" respektiert; Enrollment-Erzwingung beim Login noch nicht verdrahtet (analog Force-Change-Gate) | +| **Admin Phase 2** | Impersonation, Plan/Limits, Logo-Upload, DSGVO-Export/Retention | +| **NIS2-Modul** | nie begonnen (großes Framework, Incident-Reporting mit Fristen-Timern) | +| **Richtlinien-Versionierung/Diff, DOCX/PDF-Export** | offen | +| **ISB-Freigabe der neuen GAP-Texte** | fachlicher Prozessschritt (kein Code): neue/geänderte VA-/Richtlinien-Texte durch den ISB freigeben | +| **Platzhalter-Module** | SoA & Controls, Vorfälle, Nachweise, Management-Review, KI-Chat | + +--- + +## 3. Für neue Entwickler — technische Landkarte + +> Setup, Stack, Konventionen und Fallstricke unverändert in **`docs/HANDOVER-DEV.md`** (§1–§9). Hier nur, was `dev` ergänzt. + +### 3.1 Neue Datenmodelle (Prisma) + +| Modell | Zweck | Mandantengebunden? | +|--------|-------|--------------------| +| `PlatformAdmin` | Getrennter Superadmin-Store (kein `tenant_id`), Argon2id, TOTP-Secret, Recovery-Codes, Lockout | nein (plattformweit) | +| `PlatformSetting` (Singleton) | Plattform-Policy, u. a. `mfaRequired` | nein | +| `Task` / `TaskComment` | Generisches Aufgaben-/Freigabe-Modell (erster Typ `policy_approval`), Kommentar-Historie | ja | +| `ManagedRegister` / `RegisterRow` | Generisches editierbares Register (code, columns JSON, Cross-Links supplier/asset) | ja | +| `SoftwareProfile` | 1:1 zu `Asset` (Typ SOFTWARE): Anbieter-Verknüpfung (`providerAssetId`→SUPPLIER), Version, Freigabestatus (`SoftwareApprovalStatus`), Freigeber, Kritikalität, Review | ja | +| `ProjectProfile` | 1:1 zu `Asset` (Typ PROJECT): IS-Klassifizierung, ISB-Einbindung, `ProjectStatus`. Kritikalität via C/I/A am Asset, Risiken via `RiskAsset` | ja | +| `AssetType` neu | Enum um `SOFTWARE` und `PROJECT` erweitert | — | +| `User.*` neu | `mustChangePassword`, `mfaEnrolledAt`, `recoveryCodes` | ja | +| `PolicyDocument.archivedAt`, `PolicyRequirement.archivedAt` | Lifecycle für nicht-destruktiven Re-Import (deaktivieren statt löschen) | ja | +| `AuditLog.tenantId` nullable | Plattform-Ereignisse ohne Mandantenbezug (`scope=platform`) | — | +| `WizardScope` (A2) | Scope des Onboarding-Wizards: Prüfziele, Geltungsbereich, Standorte, Ausschlüsse — Basis der Scope-Filter-Engine (`scope-filter.ts`) | ja (RLS) | +| `ImplementationHint` (B5) | Globaler C6-Umsetzungshinweis-Katalog je Anforderung (organisatorisch/technisch/Nachweise/Ressourcen, AL-Filter) | nein (globaler Katalog, kein RLS) | +| `PolicyPackageState` (B6) | Je Mandant: Version/Stand des importierten Vorlagenpakets — Basis für kontrollierte Diff-Übernahme von Updates | ja (RLS) | +| `ControlAssessment` (A7) | Je Mandant/Control: Belegstatus, Reifegrad (R0–R3), Zielreifegrad — Basis für Gap-Aufgaben und SoA | ja (RLS) | +| `RiskCatalogEntry` (A6) | Globaler Standard-Risikokatalog (C4) zum Übernehmen — Content identisch je Mandant | nein (globaler Katalog, kein RLS) | +| `ControlImplementation` (#10) | Je Mandant/Control-Spiegelstrich: Umsetzungsstatus (dokumentiert/abgehakt), koppelt an Reifegrad und Aufgaben | ja (RLS) | +| `Task.description` (7-9) | Beschreibungsfeld am bestehenden `Task` (Migration `task_description`) für die Aufgaben/Maßnahmen-Parität | ja | +| `Risk.acceptedAt/By/Rationale` (A6) | Restrisiko-Akzeptanz-Felder am bestehenden `Risk` (Migration `risk_acceptance`) | ja | + +Alle neuen tenant-gebundenen Modelle sind in **`TENANT_MODELS`** (`src/server/db.ts`) und haben **RLS-Policies** (in den jeweiligen Migrationen). + +### 3.2 Auth-Architektur (wichtig!) + +- **Zwei getrennte NextAuth-Instanzen:** Mandanten-Login (`src/server/auth.ts`, `/login`) und **Plattform-Login** (`src/server/platform-auth.ts`, eigener Cookie + basePath `/api/platform-auth`, `/platform/login`). Plattform-Session trägt **keinen** `tenantId`. +- **Superadmin-Bereich** liegt unter `src/app/(platform)/…` (Layout erzwingt Plattform-Session + ggf. MFA); Mandanten-App unter `src/app/(app)/…`. +- **MFA-Helfer** `src/server/mfa.ts` (otplib TOTP + Recovery-Codes) — von Plattform- und Nutzer-MFA gemeinsam genutzt. +- **Force-Change:** `(app)`-Layout prüft Kontostatus/`mustChangePassword` autoritativ aus der DB → `/change-password` bzw. Abmelde-Screen bei deaktivierten Konten. +- **Passwort-Policy:** `src/lib/password-policy.ts` (reine Validierung, client-safe) + `src/server/password.ts` (Argon2id + Generator); Quelle `TenantSettings.securityPolicy.password`. + +### 3.3 Modul-Durchsetzung (§3.4) — Konvention für neue Actions + +- Jede mutierende Server-Action eines **gegateten Moduls** läuft über `moduleGuard("")` (`src/server/action-guard.ts`): Session → `assertModuleEnabled` → RBAC. +- **Vollständigkeitscheck** `scripts/check-module-guards.ts` (als `prebuild` verdrahtet): jede Datei in `src/server/actions/` muss dort eingetragen sein (Modul-Key oder `EXEMPT`), sonst **failt der Build**. → Neue Action-Datei? Dort eintragen. +- Neues Modul **`tasks`** in `src/lib/modules.ts` (für Bestands-Tenants per Default aktiv, da fehlende `TenantModule`-Zeile = aktiv). + +### 3.4 Wo liegt was (neu) + +- **Superadmin/Plattform:** `src/app/(platform)/admin/**`, `/platform/{login,enroll-mfa,profile}`, `src/server/actions/{admin,platform,platform-users}.ts`. +- **Benutzer-/Rollenverwaltung (Kunde):** `src/app/(app)/settings/users/`, `src/server/actions/{tenant-users,account}.ts`, Komponenten `user-table.tsx`/`user-forms.tsx`/`role-manager.tsx`. +- **Aufgaben/Freigabe:** `src/app/(app)/tasks/`, `src/server/actions/tasks.ts` (+ `submitForApproval` in `policies.ts`); Dashboard-Kachel in `dashboard/page.tsx`. +- **Register:** `src/components/generic-register.tsx`, `src/server/actions/register.ts`, Definitionen in `prisma/import-managed.ts` (`GENERIC_REGISTERS` + `RETIRED_REGISTERS`-Cleanup). +- **Software (Lieferantenbereich):** Tab in `src/app/(app)/suppliers/page.tsx` (`?tab=software`), `src/components/software-modals.tsx`, `src/server/actions/software.ts`, `SOFTWARE_INCLUDE` in `src/lib/supplier-include.ts`. +- **Projekte (Assetinventar):** Typ-Filter/Popup in `src/app/(app)/assets/page.tsx`, `src/components/project-modals.tsx`, `src/server/actions/projects.ts`, `PROJECT_INCLUDE` in `src/lib/supplier-include.ts`. +- **Kritische IT-Dienste:** Auto-Sicht-Zweig in `src/app/(app)/assets/page.tsx` (`?view=critical`) — abgeleitet aus Verfügbarkeit + BIA (`ProcessAsset`→`Process`→`BiaEntry`); Link-Ziel von `resolveLink("REG-CRIT-SERVICES")`. +- **Richtlinien-Import (nicht-destruktiv):** `prisma/import-policies.ts` (Diff/Upsert, `{ dryRun }`, Änderungsreport, `archivedAt`). +- **Richtlinien-Import/Upload (B4):** Actions `src/server/actions/policy-package.ts` (Import-Kapselung: Self-Service `importPolicyPackage` + Plattform `importPolicyPackageForTenant`) und `policy-upload.ts` (`uploadOwnPolicy`); Aktivierungs-Trigger in `toggleTenantModule` (`admin.ts`); Storage-Adapter `src/server/storage/adapter.ts` (Stub, Epic S1); UI `src/app/(app)/policies/page.tsx` (Buttons + Report-Banner) + `src/app/(app)/policies/upload/page.tsx`. Eigene Uploads liegen im Namensraum `EIG-*` (außerhalb des Paket-Namensraums → vom Re-Import unberührt). +- **Branding (in `dev`):** Tokens in `src/app/globals.css` (`--brand-*` / `--ui-*`) mit JS-Pendant `src/lib/brand.ts`; Komponenten `src/components/brand/{certvia-logo,tenant-brand,powered-by-gefim}.tsx`; Assets `public/assets/logo/`, `public/favicon/`, `public/site.webmanifest`; Dokument-/Mail-CD `src/lib/{document-brand,email-brand}.ts`; Doku `docs/BRANDING-CERTVIA.md` (+ Design-Paket unter `docs/branding/`). +- **Vorlagenpaket (Source of Truth):** `seed/isms-vorlagenpaket-v2/` — 28→**37 Dokumente** (VA-14..19; **P01/D01/VA-20** neu für Prototypen-/Datenschutz, B4-3), `mapping.json` (321 Anforderungen), `variables.schema.json`, Baseline, Nachweisregister, **`_verify.py`** (Rendering-/Anker-Check; nach Änderungen `python3 _verify.py` → **OK**). + +### 3.5 Konventionen / Fallstricke (Ergänzungen) + +- **Dev-Server & Server-Actions:** Änderungen an Server-Actions greifen im Turbopack-Dev manchmal erst nach **Neustart** des Dev-Servers. +- **Migrations-Flow Prisma 7** wie gehabt (`migrate diff --from-config-datasource … --to-schema … --script`, dann RLS-DO-Block manuell anhängen, `migrate deploy`). Data-Migrationen (z. B. `strip_tool_variable_articles`) sind reine SQL-`UPDATE`-Migrationen. +- **Geteilte DB bei paralleler 2-Lane-Entwicklung (Dev A × Dev B):** Beide Worktrees zeigen auf **dieselbe** lokale Postgres-DB. Dadurch enthält `migrate diff --from-config-datasource` **fremde**, vom anderen Branch angewandte Schemaänderungen (z. B. wollte A1-1 fälschlich Dev Bs `tasks`-Spalten `links/origin/priority/resources` droppen). **Regel:** beim Erzeugen einer Migration nur die **eigenen** DDL-Blöcke übernehmen und Fremd-Drops von Hand entfernen; anschließend prüfen, dass die Spalten/Objekte des anderen erhalten sind. Migrations-Reihenfolge & „nie gleichzeitig" strikt nach Contracts §6. **Merge-Nachsorge:** Wird eine Migration im anderen Branch neu erzeugt (anderer Timestamp) und die geteilte DB hat noch die alte angewandt, meldet `migrate status` „applied ≠ lokal". Fix ohne Datenverlust: stalen `_prisma_migrations`-Eintrag löschen + `prisma migrate resolve --applied ` (kein SQL läuft neu). So geschehen bei `tasks_wizard_fields` (`…103650` in DB → `…104412` committet). +- **Zentrale Variablen** (Organisation/Rollen/Schutzbedarf-Flags, `src/lib/policy-variables.ts`) sind im Richtlinien-Editor gesperrt und werden serverseitig geblockt — nur in `/settings` pflegbar. +- **Rendering (Variante B):** Tool-Variablen-Defaults ohne führenden Artikel (`TOOL_TICKET`=„Ticketsystem" etc.); der Fließtext setzt Artikel/Deklination. Bestandswerte werden per Migration migriert. +- **Register vs. Managed-Register-Docs:** die verwalteten Register (CRYPTO/RISKMATRIX/CLASSIFICATION/HANDBUCH) sind spezifische Modelle; die verbliebenen `REG-*` (SENS-ROLES, AUDIT-PLAN, NET) nutzen das **generische** `ManagedRegister`-Modell. `importPolicies` archiviert nur den Paket-Namensraum (L00/R*/VA-*/BASELINE/NACHWEIS) — Register bleiben unberührt. +- **Register-Konsolidierung (Block 5):** REG-EXT-SERVICES / REG-SW-WHITELIST / REG-CRIT-SERVICES / REG-PROJECTS sind **stillgelegt** (Liste `RETIRED_REGISTERS` in `import-managed.ts` löscht Dokument + `ManagedRegister` + Zeilen idempotent beim Import). Ihre `{{LINK:REG-…}}` in den Seed-Texten bleiben unverändert — nur `resolveLink` (`src/lib/policy-render.ts`) biegt sie auf die Modul-Routen um (`/suppliers?tab=services|software`, `/assets?view=critical`, `/assets?type=PROJECT`). Wer ein Register neu stilllegen will: Code aus `GENERIC_REGISTERS` entfernen, in `RETIRED_REGISTERS` eintragen, `resolveLink`-Fall ergänzen. +- **Software/Projekte als Asset-Typen:** folgen exakt dem bestehenden Muster von SUPPLIER/IT_SERVICE (Asset + 1:1-Profil, `refNo` je Mandant, Cockpit-Popups auf `/suppliers` **und** `/assets`, backHref-gesteuert). Neue Action-Dateien (`software.ts`→`suppliers`, `projects.ts`→`assets`) sind in `scripts/check-module-guards.ts` registriert. + +### 3.6 Demo-Logins (Passwort `Demo1234!`) + +- Mandanten-Login `/login`: `admin@demo.example` (Mandanten-Admin + ISB), **`bea.approver@demo.example`** (ISB, zweiter Freigeber für den Vier-Augen-Workflow), `auditor@…`, `owner@…`, `user@…`. +- Plattform-Login `/platform/login`: `admin@demo.example` (getrennte Session; MFA optional, Enrollment beim ersten Login nur wenn Policy es verlangt). + +--- + +## 4. Commit-Übersicht (`main..dev`, neueste zuerst) + +``` +55260a7 Merge SEC3+SEC4 (MFA pro Mandant erzwingen, WebAuthn/Passkeys, TOTP-Verschlüsselung at rest, Plattform-Admin-Verwaltung) in dev +8a154f0 Merge TISAX v7-Fortsetzung (Fachbereich-Ableitung beim Import, Richtlinien nach Fachbereich im Onboarding, parametrisierbares Redirect-Ziel) in dev +a0c0d14 Merge TISAX v6/v7 (ABGABE-xlsx-Export, echter MinIO/S3-Adapter, PolicyDocument.domain/Fachbereich, Audit-Permissions) in dev +850b691 Merge TISAX v5 (Audit-Vorbereitung Phase 1: Audit-Übersicht/Wizard-Shell, Readiness/GAP-Tab, Nachweise-Tab, Control-Beschreibungen mit KI-Entwurf + ABGABE-CSV-Export) in dev +6370cee Merge TISAX v4 (Prozesshaus-Ausbau: Löschen, Katalog-Teilprozesse parentCode, Details-Overlay; BIA-Popup vereinfacht + Träger-/Risiko-Neuanlage) in dev +23df560 Merge TISAX v3 (Prozesshaus + geführtes BIA je Prozess, Popup-Bearbeitung Rollen/Kriterien, zusätzliche Prozess-Felder) in dev +f1c11aa Feature: Plattform-Konsole legt Tenant-Nutzer per Einladungslink an (wie Mandanten-Admin) +2bfc071 Merge TISAX-Integration (M0–M4 + Wizard-Neustruktur) in dev — Fundament, Strukturanalyse, Cockpit (RACI/Evidence), Audit-Wizard, TISAX-Tasks, Content-Seed; 3 Migrationen + RLS für neue Tabellen +2fd522c Feature: Benutzer-Anlegen verschickt Einladungslink per Mail (invitation-Template, /reset-Token 7 Tage) statt Passwort-Anzeige +4d28c86 Fix: Benutzer-/Mail-Actions graceful statt Fehlerseite + Formular-Werterhalt +6b4c6fb Coolify: Mail-Worker-Service (SEC1) ergänzt +c47ace0 Merge SEC1+SEC2: Mailversand/Queue (SEC1, BullMQ/ioredis/nodemailer, Worker) + Auth-Self-Service (SEC2, AuthToken, Reset/Passwortwechsel/E-Mail-Änderung, Session-Invalidierung, Rate-Limit) in dev +3998f9f Fix: /tasks SSR-Crash — entfernte Variable `open` im Untertitel wiederhergestellt +3932ff2 Merge 7-9/4: Aufgaben als Kanban-Board (Maßnahmen-Design) + Vorschläge/Bearbeiten korrigiert in dev +00e7e79 Dockerfile: Fachcontent (docs/wizard-uebergabe) ins migrate-Image für Demo-Seed (C4/C6) +fb1935e Dockerfile: Richtlinien-Vorlagenpaket (seed/) in migrate- und runner-Image +d0dfe0b Merge Security: P1/P2/P3-Härtungspaket (F-01…F-20) in dev — Tenant-Isolation, Auth/Session, RLS scharf (F-04), moduleGuard-DB-Authz (F-06), Web-Härtung, MFA-Replay, Supply-Chain/Container (F-11/F-18) +63b583d Merge Dev-A: A6-1 + A6-2 (Standard-Risikokatalog C4, Standardmaßnahme→Aufgabe, Restrisiko-Akzeptanz) in dev +e6c5e51 Merge Dev: UX-Fixes (#1/#3/#6) + Aufgaben/Maßnahmen-Vereinheitlichung (7-9) + Umsetzungshinweise Control-Schritt (#10, ControlImplementation) in dev +6b4b190 Merge Dev-B: Wizard-Schritte 4 (Richtlinien) + 6 (Risiken) — echte Komponenten statt Platzhalter in dev +0629613 Merge Branding: Umstellung auf Certvia (Design-Tokens, Logo/Icons, Metadaten, i18n, Auth-/Systemseiten, Dokument-CD) in dev +7f4a85c Merge Fix: Wizard-Bearbeitung von Validierung entkoppeln (Parallelisierung) + Rollen-Rechte-Sync-Skript in dev +6b20e13 Merge Dev-B: B7-2 (VDA-ISA-Katalog-Export CSV + Management-Zusammenfassung, C9) in dev +2cc422c Merge Dev-A: A8-1/A8-2 (Gap-Konsolidierungs-Engine) + A8 (Gap-Schritt 8: Aggregation/Priorisierung/Task-Abgleich) in dev +76cfebc Merge Dev-A: A5-1 (Asset-Schritt) + A7-1/A7-2 (Control-Assessment + Reifegrad-Engine) in dev +7dc5ae1 Merge Dev-B: B6 (Vorlagenpaket-Versionierung + kontrollierte Diff-Übernahme) in dev +1238564 Merge Dev-B: B7-1 (Assessment-Readiness-Dashboard + Interpretationstexte C9) in dev +de76856 Merge Dev-A: A4 (ISMS-Rollen Schritt 3 + Funktionstrennung FT-01…06) in dev +012c0fa Merge Dev-B: Prüfziele als Single Source aus WizardScope (Doppelquelle behoben) in dev +227d7a3 Merge Dev-A: A3-1 (generisches Objekt-Review / Validierungs-Workflow) in dev +8c9f648 Merge Dev-B: B5-1 + B5-2 (Umsetzungshinweise C6, kontextsensitives Panel) in dev [+ 98d5e26 B5-1, 93e2f44 B5-2] +d5c11df Merge Dev-A: A2-1 + A2-2 (Assessment-Level zentral, Scope-Filter) in dev [+ 69cc25a A2-1, 177df8b A2-2] +78be114 Doku: STAND B4 · c473cad B4-3 (P01/D01/VA-20) · eb7c899 B4-2 (Upload) · 269506b B4-1 (Import) — Dev B, per FF in dev +4e1b116 Merge Dev-B: B3 Fragebogen (Schritt 2 context) in dev [+ f818093 B3-Feature-Commit] +872c35e Merge Dev-B: F3+B2 Regel-/Mapping-Engine in dev [+ 20afd63 B2-Feature-Commit] + (DevOps-Integration: dev-b2-regel-engine + dev-b3-fragebogen additiv gemergt; Gate grün) +b9d8027 Story A1-2: Dashboard-Kachel „Onboarding-Fortschritt" (Dev A) +949d7c5 Story F2: ObjectReviewStatus + external_validator + Wizard-Validierung (Dev A) +12c94fe Merge Dev-B-Lane in dev: F1 + B1 + F4 (Konsolidierung beider Lanes) +0d52090 F4: Wizard-Flags in variables.schema.json (Dev B) +ddd2dc4 B1: Auto-Generierung von Aufgaben-Vorschlägen (C2 §8) (Dev B) +30c3638 F1: Task-Objekt um Wizard-Felder erweitern (Contracts §1) (Dev B) +97b3b4e Story A1-1: Onboarding-Wizard-Shell (Step-Registry, State-Machine, Gate) (Dev A) + (darüber Wizard-Kickoff-Commits: Sign-off, Dev-B-Bestätigung, Contracts, Übergabepaket) + (sowie lokale Doku-Commits — Onboarding-Prompt + STAND-Updates) +f368d8f Fix: Fonts selbst hosten (next/font/local) + Bootstrap an Superadmin-Store anpassen +cc8d486 Feat: Prod-Bootstrap (Erst-Superadmin) + Contabo-Runbook +── ab hier auf origin/dev (gepusht) ── +9b479ab Software und Projekte als Assets + Auto-Sicht kritische Dienste +150a1d9 Register-Konsolidierung: 4 Register in Fachmodule überführt +0806030 Datenmodell: Asset-Typen SOFTWARE und PROJECT mit Fachprofilen +2ec0230 Doku: Konsolidierte Übergabe des dev-Stands (PM + neue Entwickler) +95d4479 GAP WP3.1: IMPL-Texte mit verwalteten Registern verdrahtet +bd56a47 GAP WP3.0: Generisches, editierbares Register-Datenmodell + Editor +b9784e5 GAP E2: ISA 3.1.3-Stub entfernt (3.1.2 deprecated) +b7d5df4 GAP WP2.2 (Rendering Variante B) + WP4 (Feinschliff) +36c2903 GAP WP1: Neue VAs 14–19 + Register + Baseline + Eltern-Wiring +522508a GAP WP2.1: Inline-VA-Verweise + Verify-Fix (F17) +742277f Doku: Benutzer-Popups, Aufgaben-Modul, Richtlinien-Governance, Demo-Approver +1d8f563 Freigabe-Workflow + Aufgaben-Modul + Dashboard-Kachel +73c9813 Benutzerverwaltung als Popup (Einstellungen + Admin) +959d816 Richtlinien-Fixes: zentrale Variablen, Schutzbedarf zentral, Coverage nach Level +d38b265 Benutzer bearbeiten (Name/E-Mail) + Kern-Einstellungen nur Superadmin +303dcd0 Doku: Produktionshärtung + Benutzer-/Rollenverwaltung +d0821e2 Paket B — Mandanten-Admin: Benutzer- & Rollenverwaltung +3db820e Paket C — MFA optional (Superadmin + Tenant) +908b098 Paket A — Plattform-Admin: Benutzerverwaltung je Mandant +db36c79 Fundament Benutzer-/Rollenverwaltung: Schema, Passwort-Policy, Force-Change +e07dcd9 Nicht-destruktiver Richtlinien-Re-Import (Härtung Paket 3) +8e4040d Separater Superadmin-Store + eigener Login + MFA (Härtung Paket 2) +8348764 API-seitige Modul-Durchsetzung (§3.4, Härtung Paket 1) +``` + +--- + +## 5. Deployment & Verifikation + +- **Test-/Coolify-Deploy (Demo):** `dev` deployen; die 7 neuen Migrationen laufen automatisch im Init-Container (`prisma migrate deploy`), Bootstrap-Seed legt Demo-Daten + Demo-Approver an. Die letzte Migration ändert das `AssetType`-Enum und legt zwei RLS-Tabellen an — einmal komplett durchlaufen lassen, bevor die neuen Ansichten getestet werden. +- **Prod-Deploy (ohne Demo-Seed):** Runbook **`docs/DEPLOY-PROD-CONTABO.md`**. Statt Demo-Seed läuft `scripts/bootstrap-admin.ts` (Erst-Superadmin im `platformAdmin`-Store + Mandant/Mandanten-Admin, idempotent), gesteuert per `BOOTSTRAP_*`-Env im `migrate`-Job der `docker-compose.coolify.yml`; Env-Referenz `.env.prod.example`. Fonts sind selbst gehostet (kein Google-Fonts-Fetch zur Build-Zeit → reproduzierbarer Offline-Build). +- **Lokale Verifikation:** `npx tsc --noEmit` → `npm run lint` → `npm run build` (führt `prebuild`-Guard-Check aus); für das Vorlagenpaket `python3 seed/isms-vorlagenpaket-v2/_verify.py` (**OK** = rückstandsfrei, Mapping sauber). +- **Sync-Status (Gitea aktuell offline):** lokaler `dev` ist **27 Commits vor `origin/dev`** (inkl. der beiden Dev-B-Integrations-Merges F3+B2 und B3). Sobald Gitea erreichbar ist: **erst `git fetch`**, prüfen ob `origin/dev` noch `9b479ab` ist (bzw. ob jemand anderes gepusht hat), dann `git push origin dev`. Bei Divergenz nicht blind force-pushen — abstimmen. +- **Merge `dev` → `main`:** liegt beim PM/Lead (Gitea-PR: `…/msolarczek/ISMS-Tool/pulls/new/dev`). + +--- + +## 6. Empfohlene nächste Schritte + +1. **ISB-Freigabe** der neuen/angepassten Richtlinien- und VA-Texte (fachlich, inkl. **P01/D01/VA-20** aus B4-3). +2. **Storage-Backend (Epic S1)** — echten Adapter hinter `src/server/storage/adapter.ts` (B4-2-Stub) einhängen (S3/MinIO/Coolify-Volume); danach Datei-Persistenz eigener Richtlinien + Netzplan-Upload REG-NET. +3. **Wizard-Stories vollständig konsolidiert** — Dev A: A1–A8, Dev B: F1–F4, B1–B7 (inkl. B7-2 Export + Prüfziel-Follow-up). **Alle Feature-Branches in `dev`.** Als Nächstes (neue Stories/Epics): SoA-/Reifegrad-Auswertungen auf Basis von A7, Reporting-Ausbau auf Basis des VDA-ISA-Exports, echtes Storage-Backend (Epic S1). +4. **Paket 4** — SMTP + E-Mail-Einladungs-/Aktivierungs-/Reset-Flow (Aktivierung ist bereits gekapselt). +5. **Tenant-weite MFA-Pflicht** scharfschalten (Enrollment-Gate). +6. **Admin Phase 2** (Impersonation, Plan/Limits) oder **NIS2-Modul** — je nach Vertriebs-/Compliance-Priorität. + +## Hotfix: Docker-Build brach ohne PASSWORD_PEPPER ab (Deploy-Blocker) +- **Symptom:** Coolify-Deploy „erfolgreich", aber KEINE certvia-Container. Ursache war der Image-Build selbst: `RUN npx prisma generate && npm run build` (Dockerfile:40) exit 1 → kein `up`. +- **Root Cause:** `src/server/auth.ts` erzeugte den Konstant-Zeit-Dummy-Hash auf **Modulebene** (`const DUMMY_HASH_PROMISE = hashPassword(...)`). `hashPassword()` liest den `PASSWORD_PEPPER`, der zur Docker-**Build**-Zeit fehlt (nur `DATABASE_URL`-Platzhalter gesetzt). `next build` (Page-Data-Collection für `/api/auth/[...nextauth]`) lud das Modul → Import-Zeit-Throw (fail-secure) → Build-Abbruch. Lokal grün, weil `.env` den Pepper liefert (im Image per `.dockerignore` ausgeschlossen). +- **Fix:** Dummy-Hash lazy + memoisiert (`dummyHash()`), Aufruf erst zur Laufzeit in `verifyIdentityPassword` — gleiches Muster wie `assertSecureEnv()`/`pepper()`. Konstant-Zeit-Verhalten (F-05) bleibt erhalten. +- **Verifiziert:** `docker build --target builder` grün OHNE gesetzten `PASSWORD_PEPPER` (Coolify-Build-Bedingung); tsc grün. + +## Hotfix 2: incident-inbound-worker Crash-Loop riss den Stack ab +- **Symptom (nach Build-Fix):** migrate ✅, app ✅ `Ready`, mail-/backup-worker ✅ — aber Coolify-Status flippte auf „exited" und riss den ganzen Stack ab. Ursache: `incident-inbound-worker` ohne IMAP-Konfig `process.exit(1)` + `restart: unless-stopped` → Crash-Loop → Coolify wertet Deploy als unhealthy → `compose down` (auch der gesunden App). +- **Fix:** `scripts/incident-inbound-worker.ts` idlet jetzt bei fehlender IMAP-Konfig (`idleUntilSignal()`), statt zu exiten. Container bleibt „running", SIGTERM beendet sauber (Exit 0). Bei nachträglicher IMAP-Konfig: Container-Neustart aktiviert den Betrieb. +- **Verifiziert:** tsc grün; Smoke-Test ohne IMAP-Env → Prozess bleibt am Leben, loggt Idle-Hinweis, kein Crash. + +## Merge: Objektspeicher MinIO → Garage (self-hosted) +- feature/garage-migration → dev (`--no-ff`). Umsetzung des Konzepts `docs/KONZEPT-garage-migration.md` (4 Lanes), keine Datenmigration (nur Test-Instanzen, Neu-Deploy). +- **Infra:** `garage`-Service ersetzt `minio` in `docker-compose.yml` + `docker-compose.coolify.yml`; `deploy/garage.toml` (Single-Node, `s3_region=us-east-1`, RPC-/Admin-Token); Volumes `garage_meta` (kritisch, ins Backup) + `garage_data`. +- **Provisioning:** `scripts/garage-provision.ts` — idempotenter Init-Job (Layout + Bucket `isms-documents` + Key-Import aus S3_*-Env + Rechte). +- **App-Code:** `ensureBucket()` in `adapter.ts` + `backup-store.ts` nur noch verifizierend (HeadBucket), **kein** S3-`CreateBucket` mehr (Garage kann das nicht); fehlender Bucket → sprechender Konfigfehler statt stiller Heilung. `CreateBucketCommand`-Imports entfernt. +- **Test/Doku:** `scripts/test-garage-storage.ts` (skippt ohne `S3_ENDPOINT`, echter E2E mit gesetzten S3_*), Runbook in `docs/DEPLOY-COOLIFY.md`. +- **Gate grün:** tsc, lint, build, Storage-Smoke-Test. +- **Deploy-Hinweise:** Coolify-Env `S3_ENDPOINT=http://garage:3900`, `S3_REGION=us-east-1`, `GARAGE_RPC_SECRET`/`GARAGE_ADMIN_TOKEN` **literal** setzen (Interpolationsfalle); `minio`-Service erst nach Abnahme entfernen (Rollback-Netz). + +## Hotfix Garage-Deploy: garage.toml ins Image backen (Coolify-Bind-Mount-Falle) +- **Symptom:** `garage`-Container crasht ~2s nach Start → unhealthy → Deploy bricht ab. Log: `Error: IO error: Is a directory (os error 21)` nach „Loading configuration…". +- **Ursache:** Coolify legt die Quelle des relativen Bind-Mounts `./deploy/garage.toml` als **Verzeichnis** an (Storage-Behandlung) → Garage bekommt `/etc/garage.toml` als Ordner. +- **Fix:** Neue Dockerfile-Stage `garage` (`FROM dxflrs/garage:v1.2.0` + `COPY deploy/garage.toml /etc/garage.toml`); `docker-compose.coolify.yml` nutzt `build: target garage` statt `image:` + Bind-Mount. Secrets bleiben zur Laufzeit aus `GARAGE_RPC_SECRET`/`GARAGE_ADMIN_TOKEN`. Lokales `docker-compose.yml` behält den Bind-Mount (auf normalem Docker unkritisch). +- **Verifiziert:** `docker build --target garage` + Start mit gültigem Secret → Daemon läuft, `/garage status` Exit 0. + +## Merge: Framework-Erweiterung — ISO 27001 neben TISAX (AP1–AP5 + B1) +- Kumulativer Merge von `feature/framework-assessment` (enthielt alle Framework-Lanes: iso27001-framework-mapping, framework-core, ap2, ap3-soa, ap4-mgmt, ap5-doccontrol, assessment) → `dev` (`--no-ff`, a747b57). 150 Dateien. +- **AP1** Framework-Dimension (`TenantFramework`, `PolicyTemplateVersion.framework`), **AP2** Provisionierung & Framework-Flags + framework-fähiger Vorlagen-Editor, **AP3** SoA-Modul (ISO-Anwendbarkeitserklärung, 93 Annex-A-Zeilen), **AP4** Managementklauseln (9.1/9.3/10.2, CAPA + Wirksamkeitsprüfung), **AP5** Dokumentenlenkung (Prüfzyklen, Versionshistorie, Lesebestätigungen), **A1–A4/B2/B3** ISO-Inhalte, **B1** Assessment-/Readiness-Strategie-Schicht. +- **Variante A** (Konzept D4): ein Dokumentensatz, zwei Mappings — `docs/FRAMEWORK-MAPPING-ISO27001.md`, `docs/KONZEPT-framework-iso27001.md`. +- **Gate grün:** tsc, lint, build. Neue Tests grün: `test-framework-{core,templates,provision,assessment,dryrun}`, `test-{assessment-iso,soa,doc-control,review}`. **TISAX-Snapshot-Regression: 0 Abweichungen** (45 Controls, AL2) — TISAX-Verhalten bit-genau erhalten. + +## Fix: Normen (Frameworks) je Mandant nachträglich umschaltbar +- `cb2bc0b` Admin-Action + UI (`admin/[id]/page.tsx`, `actions/admin.ts`, i18n de/en): ISO/TISAX pro Mandant nachträglich aktivieren/deaktivieren. `1475193` Abnahmetest-Fix: „wiedererkannt" zählt reaktivierte Dokumente mit. +- Neuer Test `scripts/test-framework-toggle.ts` (Aktivieren/Deaktivieren + Zustand wiederherstellen). Gate grün: tsc/lint/build, test-framework-toggle/-dryrun, TISAX-Snapshot 0 Abweichungen. + +## BIA-Prozessübersicht: Prozesshaus-Ansicht (Standard) + Tabellen-Umschalter +- `/processes` (`src/app/(app)/processes/page.tsx`) zeigt statt der flachen Tabelle standardmäßig ein **Prozesshaus**: Bahnen nach Kategorie (Management/Kern/Support), Hauptprozesse als aufklappbare Karten (native `
`), Teilprozesse eingerückt (Baumkonnektor). Je Hauptprozess **BIA-Rollup** aus den Teilprozessen: Kritikalität = Maximum, RTO/RPO/MTD = schärfster (kleinster) Wert; Farbcode + Statuspunkt nach `biaStatus`; Schnittstellen (`Process.interfaces`) als Chip. Umschalter „Prozesshaus ⇄ Tabelle“ über `?view=tabelle` (Prozesshaus = Default); Tabellen-Ansicht unverändert. +- **Kein Datenmodell-Umbau** — nutzt vorhandene Felder (`parentId`, `category`, `biaStatus`, `BiaEntry`). KPIs: Prozesse gesamt / im Scope / BIA vollständig / hohe Kritikalität (≥3). Modals (Detail/Anlegen/Bearbeiten) unverändert. Neue i18n-Keys unter `processes` (de/en). Gate grün: tsc/lint/build. Konzept-Mockup: `docs/MOCKUP-bia-prozessuebersicht.html`. +- **Nachtrag — jetzt umgesetzt:** strukturierte Prozess-zu-Prozess-Abhängigkeiten (siehe nächster Abschnitt); der frühere Freitext `interfaces` bleibt zusätzlich erhalten. + +## Prozess-Abhängigkeiten (strukturiert: „benötigt" / „wird benötigt von") +- Neues Modell **`ProcessDependency`** (`source` benötigt `target`, optionale `note`), Migration `20260907084110_add_process_dependencies` **inkl. RLS** (tenant_isolation + FORCE), Unique `(source, target)`, FK-Cascade beim Prozess-Löschen; in `TENANT_MODELS` aufgenommen. Auswahl **innerhalb des Mandanten**. +- Server-Actions in `actions/processes.ts`: `addProcessDependency` (idempotenter Upsert, Selbstbezug ausgeschlossen, beide Prozesse müssen existieren) und `removeProcessDependency`; `deleteProcess` löst Kanten in beide Richtungen. Beide `bia:write`-gegated + Audit-Log. +- UI: Bearbeiten-Modal neuer Abschnitt „Abhängigkeiten" (Chips + Entfernen, Auswahl-Form „benötigt: [Prozess] + Notiz", plus read-only „wird benötigt von"); Detail-Modal zeigt beide Richtungen; **Prozesshaus** zeigt „↳ benötigt: …"-Chips und „▲ N Prozesse hängen hiervon ab" (Teilprozesse kompakt inline) + Link zum Abhängigkeits-Graph. Neue i18n-Keys `deps*` (de/en). Gate grün: tsc/lint/build, Modul-Guard-Check 45 Dateien ok. +- **Netz-/Graph-Darstellung:** `buildDependencyGraph` (`src/server/dependency-graph.ts`) um Prozess→Prozess-Kanten (`ProcessDependency`, Label „benötigt von", Flussrichtung Abhängigkeit→Nutzer) erweitert; sie erscheinen im bestehenden Graphen `/dependencies` (React Flow + dagre) und fließen in Analyse/kritischen Pfad ein. SPOF-Erkennung jetzt auch für **Prozesse** (gemeinsam benötigte Prozesse wie „IT-Betrieb", von denen mehrere kritische Prozesse abhängen). Neuer Client-Filter **„Nur Prozesse"** in `dependency-graph.tsx` (blendet Assets aus → reine Prozess-Abhängigkeitskarte). Verifiziert am `demo`-Mandanten: IT-Betrieb als SPOF (3) korrekt erkannt. + +## Datenimport (Excel) — zurückgezogen +- Das zuvor auf `dev` ergänzte Excel-Datenimport-Feature (geteilte Logik `src/server/import/`, UI `/settings/import`, Ops-Skript, Tabelle `ImportRef`/Migration `20260904081701_add_import_refs`, Konzept `KONZEPT-datenimport.md`) wurde **vollständig entfernt** (nie deployt, daher ohne DB-Auswirkung). Bestandsdaten werden weiterhin über die Modul-Formulare bzw. den Onboarding-Wizard erfasst. +- `docs/HANDBUCH-KUNDENBETREUUNG.md` bleibt als produkt-/supportorientiertes Einstiegshandbuch für die Kundenbetreuung (Zugang/Rollen, Provisionierung, Framework-Wahl, Module, Onboarding, Support-Fälle, Doku-Verweise) — die Datenimport-Abschnitte wurden herausgenommen. + +## Fix: Risikokriterien 5×5 vervollständigt (Matrix ↔ Einstellungen konsistent) +- Bug: Risiko-Bewertung (Formular-Skala 1–5, Matrix 5×5, Score-Schwellen bis 25) war 5×5, aber die Kriterien-Daten nur 4-stufig geseedet (EW_LEVELS=4, Schadensdimensionen 1–4) → 5. Stufe ohne Definition. +- Entscheidung (PO): **5×5** — Kriterien ergänzen (Bewertung/Matrix/Score bleiben unverändert). +- Seed `prisma/import-managed.ts`: 5. EW-Stufe („Nahezu sicher") + 5. Stufe je Schadensdimension. +- Editor `onboarding/steps/criteria/criteria-editor.tsx` (Settings + Wizard geteilt): Typ/Update/Neuanlage/Rendering auf 1–5; `actions.ts` zod-Schema um „5"; `settings/risk-criteria/page.tsx` + `onboarding/steps/criteria/step.tsx` editorDims um „5". +- Backfill `scripts/backfill-risk-5x5.ts` (idempotent): ergänzt EW-Stufe 5 + Schadensstufe 5 für Bestandsmandanten. Für Test/Prod nach Redeploy je Instanz einmal ausführen (demo, gefim). +- Gate grün (tsc/lint/build); Backfill lokal verifiziert. diff --git a/docs/UEBERGABE-framework-iso27001.md b/docs/UEBERGABE-framework-iso27001.md new file mode 100644 index 0000000..e5cc79b --- /dev/null +++ b/docs/UEBERGABE-framework-iso27001.md @@ -0,0 +1,328 @@ +# Übergabe: Anwendung auf zwei Frameworks umbauen (ISO 27001 neben TISAX) + +**Stand:** 2026-08-21 · **Zielgruppe:** Entwickler:innen · **Vorarbeit:** Branch `feature/iso27001-framework-mapping`, Commit `492d315` + +> **Ausgangslage:** Die Inhaltsseite ist fertig. `seed/isms-vorlagenpaket-v2` trägt jetzt **zwei +> Framework-Mappings** auf **einem** Dokumentensatz — `mapping.json` (VDA ISA, 321 Anforderungen) und +> `mapping-iso.json` (ISO/IEC 27001:2022, 120 Anforderungen). Die Anwendung kennt das zweite Mapping +> noch nicht: `parsePackageFiles` liest `mapping.json` fest verdrahtet. +> +> **Auftrag:** Framework als erste Klasse im Datenmodell und in der Paketauflösung, damit ein Mandant +> ISO, TISAX oder beides führen kann. Danach die drei ISO-Artefakte, die es im Tool noch nicht gibt: +> SoA, Kennzahlen, Managementbewertung/Korrekturmaßnahmen. + +Fachlicher Hintergrund und Begründung der Entscheidung: `docs/FRAMEWORK-MAPPING-ISO27001.md`. +Gesamtarchitektur und die übrigen Lanes: `docs/KONZEPT-framework-iso27001.md`. + +--- + +## 0. Was **nicht** angefasst werden muss + +Die Paketinhalte sind generiert. Wer ISO-Texte oder Zuordnungen ändern will, ändert +`_iso_crosswalk.json` bzw. `_iso_sections.json` und lässt `python3 _generate_iso.py` laufen — +**nie direkt die Markdown-Dateien**, der Generator überschreibt sentinel-begrenzte Blöcke. + +Danach müssen beide Prüfskripte grün sein: + +```bash +cd seed/isms-vorlagenpaket-v2 +python3 _generate_iso.py # idempotent, zweiter Lauf ändert nichts +python3 _verify.py # TISAX-Sicht +python3 _verify_iso.py # ISO-Sicht +python3 _render_diff.py HEAD # TISAX-Regression gegen den aktuellen Stand +``` + +Die Sichtbarkeit im Dokument steuern zwei Variablen aus `variables.schema.json`: +`FLAG_FW_TISAX` (Default `true`) und `FLAG_FW_ISO27001` (Default `false`). + +### Parallelbetrieb ist vorgesehen + +Sind **beide** Flags gesetzt, rendert das Dokument beide Anforderungssichten untereinander — über +**einem** gemeinsamen Umsetzungstext. Genau dafür ist die Bibliothek gebaut: + +``` +3.2 Sichere Anmeldung +*Anforderungsbezug:* VDA ISA 4.1.2 · ISO/IEC 27001 A.8.5 + +**Anforderung** +*Anforderungen nach VDA ISA 2027:* +- **[MUSS]** Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt. +- **[SOLL]** Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt … +*Anforderungen nach ISO/IEC 27001:* +- **[ISO A.8.5]** Sichere Authentisierungstechnologien und -verfahren sind einzusetzen. + +**Umsetzung bei {{ORG_NAME}}** +Die Authentifizierungsverfahren sind risikobasiert ausgewählt … Passwortvorgaben nach BL-IAM-01 … +``` + +Der Anforderungsbezug steht in einer eigenen Zeile unter der Überschrift und nennt je nach +Betriebsart eine oder beide Normen. Die beiden Zwischenüberschriften erscheinen **nur**, wenn +tatsächlich beide Frameworks aktiv sind. +Die 19 ISO-only-Abschnitte kommen bei einem Doppel-Mandanten additiv hinzu. + +Auf der Datenseite ist der Parallelbetrieb erst nach AP1 möglich: `PolicyRequirement` trägt dann +beide ID-Namensräume (`4.1.2-M1` und `A.5.15-1`) nebeneinander — vorausgesetzt, Falle 1.1 ist gelöst. + +--- + +## 1. Die vier Fallen — bitte zuerst lesen + +### 1.1 `reconcilePackage` archiviert die Anforderungen des jeweils anderen Frameworks + +**Das ist der kritische Punkt.** `prisma/import-policies.ts:368-371` archiviert jede +`PolicyRequirement`, deren `reqId` nicht im importierten Paket steht: + +```ts +for (const ex of existingReqs) { + if (desiredReqIds.has(ex.reqId) || ex.archivedAt) continue; + report.requirements.archived++; + await prisma.policyRequirement.update({ where: { id: ex.id }, data: { archivedAt: now } }); +} +``` + +Ein ISO-Import in einen Mandanten mit TISAX archiviert damit **alle 321 VDA-ISA-Anforderungen** — +und umgekehrt. Die ID-Namensräume kollidieren zwar nicht (`4.1.2-M1` vs. `A.5.15-1`, `@@unique([tenantId, reqId])` +bleibt heil), aber der Abgleich muss **framework-scoped** werden: + +- `PolicyRequirement.framework Framework` ergänzen (Backfill `TISAX`), +- den Archivierungslauf auf `where: { tenantId, framework }` einschränken. + +Für **Dokumente** gilt das nicht: Beide Mappings lesen dieselben `richtlinien/`- und `verfahren/`-Dateien, +`pkg.documents` ist identisch. Ebenso Variablen, Baseline-Parameter und Nachweisregister — die sind geteilt +und dürfen genau einmal je Mandant abgeglichen werden. + +### 1.2 Zwei Unique-Constraints brechen bei zwei Frameworks + +| Modell | heute | muss werden | +|---|---|---| +| `PolicyTemplateVersion` (`prisma/schema.prisma:1639`) | `version String @unique` | `@@unique([framework, version])` — sonst kollidieren ISO 2.1 und TISAX 2.1 | +| `PolicyPackageState` (`prisma/schema.prisma:1614`) | `tenantId String @unique` | `@@unique([tenantId, framework])` — sonst merkt sich ein Mandant nur eine Paketversion | + +### 1.3 TISAX darf sich nicht verändern + +Bestandsmandanten müssen bitgenau dasselbe sehen wie heute. Der Renderdiff über alle 17 Richtlinien +(TISAX-Kontext vorher/nachher) war bei der Paketumstellung **0 Abweichungen** — dieser Wert ist die +Messlatte. `src/lib/policy-render.ts` belegt fehlende Framework-Flags bereits vor +(`FLAG_FW_TISAX = true`, `FLAG_FW_ISO27001 = false`), damit ein Bestandsmandant vor dem Paket-Re-Import +keine leeren Anforderungsblöcke sieht. **Diesen Fail-Safe nicht entfernen**, auch nicht wenn die Flags +später über `TenantFramework` gesetzt werden. + +Nebenbei: `applyProtection` (`src/lib/policy-render.ts:54`) setzt `FLAG_HIGH_PROTECTION` bedingungslos auf `true` +mit der Begründung „im TISAX-Modell stets aktiv". Für ISO-Mandanten ist das derzeit folgenlos (die +ISO-Blöcke nutzen die Schutzbedarf-Flags nicht), sollte aber beim Bau der `IsoStrategy` bewusst +entschieden werden. + +### 1.4 Migrations- und Build-Konventionen + +- Migrationsflow Prisma 7 wie in `docs/HANDOVER-DEV.md:100`: `migrate diff --from-config-datasource … --to-schema … --script`, + danach den **RLS-DO-Block manuell** an die `migration.sql` anhängen, dann `migrate deploy`. +- Jedes neue mandantengebundene Modell gehört in **`TENANT_MODELS`** (`src/server/db.ts:81`) **und** + braucht eine RLS-Policy in seiner Migration. +- `scripts/check-module-guards.ts` läuft als `prebuild`-Gate: **jede neue Datei** unter + `src/server/actions/` muss dort eingetragen sein (Modul-Key oder `EXEMPT`), sonst schlägt der Build fehl. +- Bei paralleler Lane-Entwicklung teilen sich die Worktrees dieselbe lokale Postgres-DB. Beim Erzeugen + einer Migration nur die **eigenen** DDL-Blöcke übernehmen und Fremd-Drops von Hand entfernen. +- `npm run lint` und `npm run build` müssen vor jedem Commit grün sein (`AGENTS.md:25`). + +--- + +## 2. Arbeitspakete + +### AP1 — Framework-Dimension *(Fundament, blockiert alles Weitere)* + +**Schema** + +```prisma +enum Framework { ISO_27001 TISAX } + +model TenantFramework { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + framework Framework + isPrimary Boolean @default(false) @map("is_primary") + config Json? // z. B. { tisaxLevel: "AL3" } bzw. { certScope, certBodyTarget } + createdAt DateTime @default(now()) @map("created_at") + @@unique([tenantId, framework]) + @@index([tenantId]) + @@map("tenant_frameworks") +} +``` + +Zusätzlich: `PolicyRequirement.framework`, `PolicyTemplateVersion.framework`, +`PolicyPackageState.framework` (siehe Fallen 1.1 und 1.2). Alles additiv, Backfill der Bestandsdaten auf +`TISAX`. + +**Paketauflösung** + +| Datei | Änderung | +|---|---| +| `prisma/import-policies.ts` | `parsePackageFiles(seedDir, mappingFile = "mapping.json")`; Requirements framework-scoped reconcilen | +| `prisma/template-store.ts:147` | `resolvePackageForTenant(prisma, tenantId, seedDir, framework)`; `loadPublishedPackage(prisma, locale, framework)`; `getAvailableVersion` ebenso | +| `scripts/sync-policy-templates.ts:23` | über **Frameworks × Sprachen** iterieren statt nur über Sprachen | + +Die vier Aufrufer von `resolvePackageForTenant` bekommen den Framework-Parameter durchgereicht: +`src/server/provision.ts:139`, `src/server/actions/policy-package.ts:28`, `src/server/actions/admin.ts`, +`src/app/(app)/policies/updates/page.tsx:44`. + +**Das Seed-Verzeichnis bleibt für beide Frameworks dasselbe** — die fünf `SEED_DIR`-Konstanten ändern +sich nicht, nur der Mapping-Dateiname. Das ist der Vorteil von Variante A. + +**DoD:** Bestandsmandanten laufen unverändert als TISAX; ein Mandant kann mit +`frameworks: ["ISO_27001"]`, `["TISAX"]` oder beiden provisioniert werden; bei Doppel-Framework +koexistieren 321 + 120 Anforderungen und **keine** ist fälschlich archiviert. + +--- + +### AP2 — Provisionierung und Flags *(klein, direkt nach AP1)* + +`ProvisionOpts` (`src/server/provision.ts:37`) um `frameworks: Framework[]` erweitern. +`provisionTenant` schreibt die `TenantFramework`-Zeilen, importiert **je Framework** das passende +Mapping und setzt die Sichtbarkeits-Flags als `PolicyVariable`: + +| Mandant führt | `FLAG_FW_TISAX` | `FLAG_FW_ISO27001` | +|---|:--:|:--:| +| nur TISAX | `true` | `false` | +| nur ISO | `false` | `true` | +| beides | `true` | `true` | + +**Achtung Reihenfolge:** `reconcilePackage` erhält nutzergepflegte Variablenwerte und überschreibt sie +nicht. Die Flags müssen also **nach** dem Import gesetzt werden, sonst bleibt der Schema-Default stehen +und ein ISO-Mandant sieht die VDA-ISA-Sicht. + +`tisaxLevel` bleibt vorerst auf `TenantSettings`, wird aber als TISAX-scoped dokumentiert (Entscheidung D2). +Die AL-Flags dürfen bei einem reinen ISO-Mandanten nicht gesetzt werden. + +**DoD:** Ein frisch provisionierter ISO-Mandant öffnet `/policies` und sieht in jedem Dokument die +ISO-Anforderungssicht plus die 19 ISO-only-Abschnitte; keine „ISA"-Klammern in den Überschriften. + +--- + +### AP3 — SoA-Modul *(das fehlende ISO-Kernartefakt)* + +Heute ist der Modul-Key `soa` (`src/lib/modules.ts:19`) mit `href: "/soa"` registriert, **die Route +existiert aber nicht** — die Logik liegt als Wizard-Schritt 7 in `src/server/actions/soa.ts` und ist ein +VDA-ISA-Reifegrad-Assessment (0–3), nicht die ISO-Anwendbarkeitserklärung. + +```prisma +model SoaEntry { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + framework Framework + control String // "A.5.15" + applicable Boolean @default(true) + justification String // Begründung Einbeziehung ODER Ausschluss + source String? // Risiko-ID / gesetzliche / vertragliche Anforderung + implementationStatus String @default("geplant") // umgesetzt | teilweise | geplant + ownerId String? @map("owner_id") + policyCode String? @map("policy_code") + evidenceId String? @map("evidence_id") + @@unique([tenantId, framework, control]) + @@index([tenantId]) + @@map("soa_entries") +} +``` + +Die vier Felder `applicable`, `justification`, `implementationStatus` und die Ausschlussbegründung sind +**normative Pflichtangaben** (ISO/IEC 27001:2022, 6.1.3 d) — ohne sie ist die SoA im Zertifizierungsaudit +angreifbar. + +Vorbefüllung aus `mapping-iso.json`: 93 Controls; das Feld `condition` (z. B. `FLAG_DEV_INHOUSE`) steuert +die Default-Anwendbarkeit. Als fachliche Vorlage für Aufbau und Spalten dient +`seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md`. + +**DoD:** Ein ISO-Mandant kann die SoA vollständig pflegen und als PDF/XLSX exportieren; ein Control ohne +Begründung wird als unvollständig markiert. + +--- + +### AP4 — Managementklauseln: Kennzahlen, Bewertung, Korrekturmaßnahmen + +Drei Modelle fehlen; alle drei sind ISO-Pflichtthemen und heute nicht abbildbar: + +| Klausel | Modell | Inhalt | +|---|---|---| +| 9.1 | `Kpi` / `KpiValue` | Kennzahl, Datenquelle, Zielwert, Turnus, Verantwortlicher, Messwerte je Periode | +| 9.3 | `ManagementReview` | Datum, Eingaben nach 9.3.2, Ergebnisse nach 9.3.3, Beschlüsse mit Verantwortlichem und Termin | +| 10.2 | `Nonconformity` + `CorrectiveAction` | Herkunft, Sofortkorrektur, Ursachenanalyse, Maßnahme, Wirksamkeitsbewertung | + +Vorhandene Bausteine, auf denen das aufsetzen kann: `Task.recurrence` (RRULE), `Task.remindAt`, +`Task.effectiveUntil` (Wirksamkeitsintervall, gekoppelt an `Evidence.validUntil`), `TaskParticipant` (RACI) +und `AuditLog`. Die Datenquellen für die Kennzahlen liegen bereits im Tool: Aufgabenfristen und +Überfälligkeit, Incident-SLA und Meldefristen (`src/lib/incident-deadlines.ts`), Reifegrade je Control, +Maßnahmenstatus. + +Fachlicher Inhalt der Abschnitte steht in R03 der Bibliothek (`ISO-MS-MESSUNG`, `ISO-MS-MGMTREVIEW`, +`ISO-MS-CAPA`) — die Modelle sollten die dort beschriebenen Felder tragen. + +**DoD:** Kennzahlenblatt mit Zielwerten pflegbar und über zwei Perioden auswertbar; Management-Review +entlang der 9.3.2-Agenda protokollierbar; ein Maßnahmenfall inklusive dokumentierter Wirksamkeitsprüfung +abschließbar. + +--- + +### AP5 — Dokumentenlenkung *(klein, hohe Auditwirkung)* + +- `PolicyDocument.reviewCycle` und `nextReviewAt` — heute führt nur `ManagedRegister` einen + `reviewCycle`; A.5.1 verlangt die Überprüfung „in geplanten Abständen". Behelfsweise über + `Task.recurrence` möglich, sauberer am Dokument. +- `PolicyAcknowledgement { tenantId, policyDocumentId, version, userId, acknowledgedAt }` — die + Lesebestätigung ist in `SPEC.md` §4.6 vorgesehen und fehlt. Sie ist zugleich der einfachste Nachweis + für Klausel 7.3 und Control A.6.3. +- Änderungshistorie je Dokumentversion — im Entwicklungsstand als offen geführt. Kann aus `AuditLog` + (Vorher/Nachher) abgeleitet oder als eigene Tabelle geführt werden. + +**DoD:** Übersicht „Prüfung fällig" im Tool; Auswertung der Lesebestätigungen je Richtlinienversion; +Historie eines Dokuments über mindestens zwei Versionen sichtbar. + +--- + +## 3. Reihenfolge und Aufwand + +``` +AP1 Framework-Dimension ██████ 4–6 PT ← blockiert alles + ├─ AP2 Provisionierung ██ 1–2 PT + ├─ AP3 SoA-Modul ██████ 5–8 PT + ├─ AP4 Managementkl. ██████ 5–8 PT + └─ AP5 Dok.-Lenkung ███ 2–3 PT +``` + +AP3, AP4 und AP5 sind nach AP1 parallelisierbar. Die Schätzung entspricht den Lanes 1, 4 und 5 aus +`KONZEPT-framework-iso27001.md`; der inhaltliche Teil von Lane 2 (ISO-Mapping und -Texte) ist erledigt und +entfällt. + +**Feature-Flag:** ISO bleibt laut Entscheidung D7 hinter einem Plattform-Schalter, bis AP3 abgenommen ist. + +--- + +## 4. Abnahme + +| Prüfung | Erwartung | +|---|---| +| `python3 _verify.py` und `_verify_iso.py` | beide `OK` | +| `python3 _render_diff.py ` (TISAX-Sicht) | 0 Abweichungen — Skript liegt im Paket bei. **Vergleichsstand ist der Kopf dieses Branches, nicht `a9649b3`**: der Anforderungsbezug ist dort bewusst aus der Überschrift in eine eigene Zeile gewandert (14 von 17 Richtlinien betroffen, ausschließlich diese Zeile — der Anforderungs- und Umsetzungstext ist unverändert). | +| `python3 _render_diff.py --framework BEIDE` | Parallelbetrieb prüfbar | +| `npx tsx scripts/test-framework-dryrun.ts` | alle Prüfungen bestanden — Trockenlauf ohne Schreibzugriff über Paketebene und alle Mandanten der lokalen DB | +| Bestandsmandant (TISAX) nach Deploy | Readiness und Exporte identisch zum Snapshot vor dem Umbau | +| Import ISO in Mandant mit TISAX | 120 neue Anforderungen, **0 archivierte** ISA-Anforderungen | +| Import ISO, Umsetzungstexte | 120 von 120 gefüllt (0 leer) | +| Dokumente bei Doppel-Framework | 39 Dokumente, **nicht** doppelt | +| `npm run lint`, `npx tsc --noEmit`, `npm run build` | grün | + +Der Importer lässt sich ohne Datenbank gegen beide Mappings prüfen — `parsePackageFiles` ist reine +Dateiarbeit und liefert `documents`, `requirements`, `variables`, `baseline`, `evidence` als +`ParsedPackage`. Ein Trockenlauf des Mandanten-Imports geht über `reconcilePackage(..., { dryRun: true })`; +er erzeugt den Änderungsreport ohne Schreibzugriff und eignet sich als Freigabebedingung. + +--- + +## 5. Offene Punkte auf der Paketseite (nicht Entwicklung) + +Diese Punkte gehören dem ISB bzw. der Redaktion, nicht dem Entwicklungsteam — hier nur zur Abgrenzung: + +- Nachweisregister um Zeilen für Kennzahlenblatt, Management-Review-Protokoll und Maßnahmenregister ergänzen. +- VA-15 trennen (internes Audit vs. Managementbewertung) und ein Verfahren für Korrekturmaßnahmen + ergänzen — **Nummer ab VA-21**, VA-20 ist belegt. +- `REVIEW_CYCLE` wird an 33 Bestandsstellen für fünf verschiedene Zyklen verwendet; die getrennten + Variablen (`POLICY_REVIEW_CYCLE`, `MGMT_REVIEW_CYCLE`, `RISK_REVIEW_CYCLE`) greifen bisher nur in den + neuen ISO-Abschnitten. +- ISB-Freigabe der 19 neuen Abschnittstexte und Review des Crosswalks. diff --git a/docs/UEBERGABE-identity-mandanten.md b/docs/UEBERGABE-identity-mandanten.md new file mode 100644 index 0000000..3cb1d35 --- /dev/null +++ b/docs/UEBERGABE-identity-mandanten.md @@ -0,0 +1,38 @@ +# Übergabe — Umbau „Zentrale Identität + Mandanten-Mitgliedschaften" (certvia) + +> Kurzübergabe für Team-Lead + PM + neue Entwickler. Produkt: **certvia** (ISMS-Tool). Branch: **`feature/identity-mandanten`**. + +## Worum es geht +Eine Person soll sich mit **einem** Login/Passwort/MFA anmelden und danach wählen, in **welchem Mandanten** sie arbeitet — mit je Mandant unterschiedlichen Rollen. Heute ist jeder Nutzer fest an genau einen Mandanten gebunden (eigenes Passwort/MFA je Mandant). Umbau nach **Option C**: globale `Identity` (Anmeldung) + bestehende per-Mandant-`User`-Zeilen als „Mitgliedschaften". + +## Die zwei Dokumente +1. [KONZEPT-identity-mandanten.md](KONZEPT-identity-mandanten.md) — **Entscheidungsvorlage** (fachlich, warum/was). Enthält die getroffenen Entscheidungen A–E, Two-Step-Login, Passphrasen, MFA-Matrix, die vier Anlage-Flows, Sicherheitsbetrachtung. +2. [FEINDESIGN-identity-mandanten.md](FEINDESIGN-identity-mandanten.md) — **umsetzbarer Bauplan** (technisch): Zieldatenmodell, Session-Shape, Flows, 7 Workstreams, 6 Meilensteine, Risiken, DoD, Onboarding, Aufwand (≈ 47–73 PT / ≈ 5–7 Wochen). + +## Getroffene Entscheidungen (fix) +| A | B | C | D | E | +|---|---|---|---|---| +| MFA **beim Login** (2-stufig: erst Passwort, dann MFA) | Reset-Hoheit → Self-Service + Plattform (Mandanten-Admin verliert MFA-/Passwort-Reset) | **Einladung** als Standard-Anlage | **Migration entfällt** (nur Testdaten → Reseed) | Plattform-Admins **getrennt** (`platform_admins`) | + +## Womit das Team startet (M0 → M1) +1. **Onboarding:** Pflichtlektüre `docs/HANDOVER-DEV.md` → `docs/SPEC.md` → `docs/STAND-dev-branch.md` → FEINDESIGN → KONZEPT. Dev-Setup + Gate (§10 im FEINDESIGN). +2. **WS0 Fundament als Pairing** (Lead + je 1 Dev): `Identity`-Modell, Schema-Recut, Migration, `TENANT_MODELS`, Reseed. Blocker für fast alles Weitere. +3. Danach parallel: WS1 (Auth-Kern), WS3 (Einladung), WS4 (Passwort/MFA an Identity), WS6 (Seed). + +## Die 5 „Goldenen Regeln" (nicht verhandelbar) +1. `User.id` = Mitgliedschaft, **stabil lassen**; Auth-Felder leben auf `Identity`. +2. `Identity` ist **global**, **nicht** in `TENANT_MODELS`, kein `tenant_id`, keine RLS-Policy. +3. Genau **ein** aktiver Mandant pro Session; server-autoritativ; bei Wechsel re-validieren. +4. **Keine** „Passwort direkt setzen"-Anlage mehr — nur Einladung. +5. MFA/Passwort gehören der Identity — **kein** Mandanten-Admin-Reset. + +## Warum der Umbau überschaubar bleibt +Weil `User.id` **und** die Semantik von `session.user.tenantId` (= aktiver Mandant) erhalten bleiben, sind **~356 `dbForTenant()`-Stellen, alle 6 Owner-FKs und das RLS-Modell unberührt**. Der Umbau konzentriert sich auf Login, Session-Aufbau, Mandantenauswahl und Nutzer-Lifecycle. + +## Koordination mit laufender Arbeit +- **Richtlinien-Upload im Adminportal** (parallel in Arbeit) ist **funktional nicht betroffen**: er hängt nur an `moduleGuard("policies")`, `session.user.tenantId`, `session.user.id`, `dbForTenant()` und `requirePlatformFullAdmin` — alles stabile Flächen. **Ein** Berührungspunkt: die geteilte Datei `src/app/(platform)/admin/[id]/page.tsx` (Policy-Upload an der Module-Karte, Identity-Umbau an der Benutzerverwaltung) → nur Merge-Koordination, kein funktionaler Konflikt. Empfehlung: WS3/WS-UI und der Policy-Upload-Stream stimmen Reihenfolge auf dieser Datei ab. +- **DevOps:** Feature-Branch → `git merge --no-ff` nach `dev` → Gate grün (tsc/lint/build + alle `scripts/test-*.ts`) → Push auf **beide** Remotes (`origin` git.certvia.de + `local-gitea`) → `docs/STAND-dev-branch.md` pflegen. + +## Offen für PM-Entscheidung (kein Blocker fürs Feindesign) +- Team-Besetzung/Startdatum, Sprint-Zuschnitt entlang M1–M6. +- Phase-2-Punkte (per-Mandant „immer Step-up", E-Mail-Änderung als Identity-Op, evtl. PlatformAdmin-Konsolidierung) — bewusst zurückgestellt. diff --git a/docs/branding/Aufgabenpaket-Branding-Certvia.md b/docs/branding/Aufgabenpaket-Branding-Certvia.md new file mode 100644 index 0000000..f46a01a --- /dev/null +++ b/docs/branding/Aufgabenpaket-Branding-Certvia.md @@ -0,0 +1,107 @@ +# Umsetzungspaket — Vollständige Branding-Umstellung auf **Certvia** + +> Claude-Code-Prompt für **einen** Entwickler. Basis-Branch **`dev`**, Feature-Branch **`dev/branding-certvia`** (PR-Ziel `dev`). +> Quelle der Wahrheit: **Certvia Brand-Board** (`Certvia-Brand-Board-final.html`) + Logo-SVGs (`certvia-mark-positiv/negativ/grau/anthrazit.svg`, `certvia-favicon.svg`, `certvia-lockup-positiv.svg`) aus `Certvia-Design-Uebergabe.zip`. + +## 0. Ziel & Leitplanken +Die App vollständig auf den **Certvia-Styleguide** umstellen — Logo, Wortmarke, App-Name, Favicon/Icons, Typografie, Marken-/UI-Farben, Dokument-/Export-Design und alle Texte. +**Wichtige Leitplanken:** +- **GEFIM bleibt Dachmarke.** „**Ein Produkt von GEFIM**" (inkl. GEFIM-Logo) bleibt im Footer/Impressum/Export-Fußzeile erhalten. Nur die **Produktmarke** wird Certvia. +- **UI-Farben bleiben wie initial festgelegt** (Dark-Theme-Primär `#7d6fd6` etc.) — sie **sind** die Certvia-UI-Palette. Nicht „korrigieren". Marken-Violett `#5d52a3` gilt für Logo/Print/Verläufe, UI-Interaktiv bleibt `#7d6fd6`. +- **Keine Funktionsänderung** — reines Branding/Design. Kein Umbau von Logik/Datenmodell. + +--- + +## 1. Design-Tokens (verbindliche Referenz) + +**Markenfarben (Logo, Print, Verläufe, Akzent):** +| Rolle | Hex | +|---|---| +| Violett (Marke) | `#5d52a3` | +| Magenta (Akzent: „via", Haken, Highlights) | `#812d80` | +| Hellblau | `#8dc4e0` | +| Anthrazit (Text/Headlines) | `#3b3b3a` | + +**UI Dark-Theme (unverändert, = Certvia-Produktpalette):** +`--violet:#7d6fd6` · `--violet-deep:#5d52a3` · `--blue:#8dc4e0` · `--magenta:#b45bb0` · `--bg0:#0e1220` · `--bg1:#141a2e` · `--panel:rgba(30,38,64,.72)` · `--panel-b:rgba(120,135,180,.18)` · `--elev:#1a2138` · `--txt:#e8ecf7` · `--muted:#8b93ad` · `--ok:#39c07f` · `--warn:#f0ad4e` · `--risk:#ff6b6b` · Primär-Verlauf `linear-gradient(135deg,#5d52a3,#7d6fd6)` · Fokus-Ring `rgba(125,111,214,.35)`. + +**Typografie:** Headlines/Wortmarke **Poppins**, Fließtext **Open Sans** (bereits im Einsatz — bestätigen, **selbst hosten**, kein ungefragtes Google-Fonts-CDN). + +**Logo/Marke:** C-Monogramm (offenes „C" Violett `#5d52a3` + Haken Magenta `#812d80`, Haken schließt bündig an die C-Öffnung). Wortmarke „Cert" (Poppins Light, Anthrazit) + „**via**" (Poppins Bold, Magenta). Auf dunklem Grund: C `#7d6fd6`, Haken `#d17bcf`, Text weiß. + +--- + +## 2. Story B0 — Bestandsaufnahme / Branding-Inventar (zuerst!) (S) +**Als** Entwickler **möchte ich** alle Branding-Berührungspunkte finden, **damit** nichts übersehen wird. +- Repo-weit suchen und als kurze Inventarliste (Datei → Fundstelle → Maßnahme) dokumentieren: + ```bash + rg -i "gefim" -l # Produktname vs. Dachmarke unterscheiden + rg -i "shield|logo|brand|favicon|wordmark|app[_-]?name|siteName|title" src public + rg -i "#5d52a3|#7d6fd6|#812d80|#8dc4e0|#b45bb0|#0e1220" src # hartkodierte Farben außerhalb der Tokens + rg -i "poppins|open sans|fonts.googleapis" src public + ``` +- **AK:** Inventarliste liegt vor; jede Fundstelle ist einer der Stories S1–S9 zugeordnet; klar getrennt „Produktmarke → Certvia" vs. „Dachmarke → GEFIM bleibt". + +--- + +## 3. Stories + +### S1 — Design-Tokens zentralisieren & Certvia-Palette verankern (M) +- Eine **zentrale Token-Quelle** (CSS-Variablen/`theme`/Tailwind-Config) als Single Source of Truth; hartkodierte Farben aus S0 durch Tokens ersetzen. +- Marken- vs. UI-Tokens klar benennen (`--brand-violet` `#5d52a3` vs. `--ui-primary` `#7d6fd6`), damit Logo/Print und UI nicht vermischt werden. +- **AK:** keine hartkodierten Markenfarben mehr in Komponenten; Umschalten zentral möglich; UI optisch unverändert (nur konsolidiert). + +### S2 — Logo, Wortmarke & Icons (M) +- **App-Header/Sidebar**, **Login** (`/login`) und **Plattform-Login** (`/platform/login`): GEFIM-Schild → **Certvia-Logo** (Lockup C-Monogramm + „Certvia"). Dark-Variante nutzen. +- **Favicon** + **PWA/Manifest-Icons** (`public/`, `manifest.webmanifest`, `apple-touch-icon`) auf `certvia-favicon.svg` (C auf Violett-Tile) und generierte PNGs (32/180/192/512). +- `meta-theme-color` = `#5d52a3` (schon so auf der Website). +- SVG-Assets aus dem Design-Paket in `public/assets/logo/` bzw. `src/components/brand/` einbinden; **Logo als React-Komponente** ``. +- **AK:** in allen App-Bereichen erscheint das Certvia-Logo; Favicon/Tab-Icon = Certvia; keine GEFIM-Schild-Reste in Produkt-UI. + +### S3 — App-Name, Titel, Meta & i18n-Texte (S–M) +- App-Name/``/OG-/Twitter-Meta, PWA-Name, Sidebar-Kopf, „Über"/Version-Info → **Certvia**. +- i18n (`de`/`en`): alle Produktname-Strings auf „Certvia"; Tagline „Informationssicherheit. Endlich einfach." wo passend. +- **AK:** Browser-Tab, Meta, Manifest und sichtbare Produktnamen zeigen „Certvia"; „ein Produkt von GEFIM" bleibt erhalten. + +### S4 — Typografie bestätigen & selbst hosten (S) +- Poppins (300/400/500/600/700) + Open Sans (400/600/700) **self-hosted** (woff2) statt CDN; Fallback-Stack; `font-display: swap`. +- **AK:** keine externen Font-Requests; Wortmarke „Cert**via**" korrekt (Light + Bold), Headlines Poppins, Fließtext Open Sans. + +### S5 — Dokument-/Export-Corporate-Design (M–L) +- **DOCX/PDF/Print-Export** (Richtlinien, VDA-ISA-Katalog, Reports) auf **Certvia-Corporate-Design**: Deckblatt/Kopf mit Certvia-Logo + Farben, Fußzeile „Certvia — ein Produkt von GEFIM" + GEFIM-Logo, Poppins/Open Sans. +- Betrifft den (offenen) DOCX/PDF-Export — Branding-Layer so bauen, dass er beim Export-Feature andockt. +- **AK:** exportierte Dokumente tragen Certvia-Branding; GEFIM als Dachmarke in der Fußzeile. + +### S6 — E-Mail-/Benachrichtigungs-Templates (S–M, falls vorhanden) +- Sobald SMTP/E-Mail (Paket 4) existiert bzw. für Einladungs-/Reset-Mails: Header/Footer/Farben/Logo auf Certvia; Absender-/Signatur-Text „Certvia — ein Produkt von GEFIM". +- Falls E-Mail noch nicht aktiv: nur die **Template-Basis** brandfähig vorbereiten. +- **AK:** vorhandene Mail-Templates gebranded oder brandfähige Basis vorbereitet. + +### S7 — Auth-, Fehler- & Systemseiten (S) +- Login, Change-Password, deaktiviertes Konto, 404/500, Wartungs-/Status-Banner, Loading-/Empty-States: Certvia-Logo + Palette. +- **AK:** keine ungebrandeten/gemischten Screens mehr. + +### S8 — Mandanten-Branding-Default = Certvia (S–M) +- Der Whitelabel-/Branding-Fallback je Mandant (Admin Phase 2 „Logo-Upload") ist **Certvia** als Default; Custom-Logo überschreibt nur, wenn gesetzt. +- **AK:** ohne Custom-Logo zeigt jeder Mandant Certvia; „ein Produkt von GEFIM" bleibt unabhängig davon. + +### S9 — Restliche GEFIM-Referenzen bereinigen (S) +- Alle in S0 gefundenen **Produkt**-Referenzen „GEFIM" → „Certvia" (Kommentare, Alt-Texte, aria-labels, Klassennamen unkritisch). **Dachmarken-Hinweise bewusst belassen.** +- **AK:** `rg -i "gefim"` liefert nur noch Dachmarken-Kontext (Footer/Impressum/Export-Fußzeile/Assets `gefim/`). + +--- + +## 4. QA / Definition of Done +- **Visuelles Review** der Kernscreens (Dashboard, Richtlinien, Assets, Risiken, Lieferanten, Aufgaben, Admin, beide Logins, Export, Fehlerseiten) hell **und** dunkel — Screenshots im PR. +- **Kontrast prüfen:** Magenta `#812d80` auf Weiß und `#d17bcf` auf Dunkel (WCAG AA für Text/aktive Elemente). +- `rg -i "gefim"` = nur Dachmarken-Kontext; keine externen Font-/Logo-Requests; keine hartkodierten Markenfarben. +- `npx tsc --noEmit` → `npm run lint` → `npm run build` grün; Demo-Umgebung lauffähig. +- **Reines Branding-PR** — keine funktionalen Diffs. + +## 5. Reihenfolge +S0 (Inventar) → S1 (Tokens) → S2 (Logo/Icons) → S3 (Name/Meta/i18n) → S4 (Fonts) → S7 (Auth/Fehler) → S9 (Cleanup) → S5 (Export) → S8 (Mandanten-Default) → S6 (Mail, falls vorhanden). + +## 6. Assets (mitliefern an den Entwickler) +Aus `Certvia-Design-Uebergabe.zip`: `logo/certvia-mark-positiv.svg`, `-negativ.svg`, `-grau.svg`, `-anthrazit.svg`, `certvia-favicon.svg`, `certvia-lockup-positiv.svg`, `logo/README-Logo.md`, `Brand-Board.html` (Farb-/Typo-Referenz) sowie `gefim-dachmarke/` (GEFIM-Logo für den „ein Produkt von GEFIM"-Hinweis). + +> Hinweis: Falls PNG-Rastergrößen (Favicon/Apple-Touch/PWA 32/180/192/512) benötigt werden, kann ich sie aus dem SVG erzeugen und beilegen — sag kurz Bescheid. diff --git a/docs/branding/README-Logo.md b/docs/branding/README-Logo.md new file mode 100644 index 0000000..22f7c6b --- /dev/null +++ b/docs/branding/README-Logo.md @@ -0,0 +1,29 @@ +# Certvia — Logo-Dateien + +Logo = **C-Monogramm + Haken** (Entwurf C) in GEFIM-Farben. Alle Marken (außer Lockup) sind quadratisch (viewBox 64×64), vektoriell und frei skalierbar. + +## Dateien +| Datei | Verwendung | +|---|---| +| `certvia-mark-positiv.svg` | Standard auf hellem Grund (C Violett, Haken Magenta) | +| `certvia-mark-negativ.svg` | Auf farbigem/dunklem Grund (weiß) | +| `certvia-mark-grau.svg` | Graustufen | +| `certvia-mark-anthrazit.svg` | Einfarbig Anthrazit (Dokumente/Druck s/w) | +| `certvia-favicon.svg` | App-Icon/Favicon (Monogramm auf violettem Tile) | +| `certvia-lockup-positiv.svg` | Wortmarke horizontal (Zeichen + „Certvia") | + +## Farben +- **Violett (C):** `#5d52a3` +- **Magenta (Haken & „via"):** `#812d80` +- **Anthrazit (Wortmarke „Cert"):** `#3b3b3a` +- Auf dunklem Grund/UI: C `#7d6fd6`, Haken `#d17bcf`. + +## Konstruktion / Regeln +- „C" ist **offen nach rechts**; der **Haken** liegt in der Öffnung („cert"). +- **Kein Verlauf** im Zeichen. „C" nicht schließen, nicht verzerren, Seitenverhältnis wahren. +- **Schutzraum:** mind. Höhe des Haken-Elements rundum frei. +- Wortmarke „Cert" (Poppins Light/300, Anthrazit) + „**via**" (Poppins Bold/700, Magenta). +- Hinweis: SVG-Lockup nutzt Poppins per `font-family` — beim finalen Export ggf. **Text in Pfade wandeln**, damit die Schrift überall korrekt erscheint. + +## Schrift +- **Poppins** (Wortmarke/Headlines), **Open Sans** (Fließtext). diff --git a/docs/craftvia/BRANDBOOK.md b/docs/craftvia/BRANDBOOK.md new file mode 100644 index 0000000..3354d06 --- /dev/null +++ b/docs/craftvia/BRANDBOOK.md @@ -0,0 +1,797 @@ +# Craftvia Brandbook + +**Version 1.0 · September 2026** +**Marken- und Gestaltungsgrundlage für Produkt, Website, Vertrieb und Kommunikation** + +--- + +## 1. Brandbook auf einen Blick + +Craftvia ist die digitale Einsatzplattform für Handwerks- und Servicebetriebe. Sie verbindet Büro und Baustelle, führt Aufträge vom Eingang bis zum abrechnungsfähigen Nachweis und sorgt dafür, dass Informationen dort ankommen, wo sie gebraucht werden. + +**Leitclaim:** **Handwerk. Digital auf Kurs.** +**Erklärender Claim:** **Vom Auftrag bis zur Abrechnung.** +**Markenversprechen:** Weniger Papier, weniger Rückfragen, schneller abrechnen. +**Kategorie:** Digitale Einsatz- und Auftragsplattform für Handwerk und technischen Service +**KI-Assistent im Produkt:** **Lotse** + +Craftvia gehört zur gemeinsamen Produktfamilie: + +- **Certvia** – ISMS und Informationssicherheit verwalten +- **Visitvia** – Besucher und Zutritte verwalten +- **Craftvia** – Aufträge und Einsätze verwalten + +--- + +## 2. Ausgangslage + +In vielen Handwerksbetrieben endet die Digitalisierung dort, wo der Einsatz beginnt. Auftragsinformationen liegen im Büro, Stundenzettel reisen wochenlang im Fahrzeug mit, Fotos bleiben auf privaten Geräten und Materialangaben müssen nachträglich rekonstruiert werden. Erst wenn alle Nachweise vollständig sind, kann die Rechnung entstehen. + +Das führt zu wiederkehrenden Problemen: + +- Informationen werden doppelt erfasst oder gehen verloren. +- Monteure arbeiten mit unvollständigen oder veralteten Unterlagen. +- Das Backoffice muss fehlenden Angaben hinterhertelefonieren. +- Arbeitszeiten, Material und Fotos treffen verspätet ein. +- Tages- und Abschlussberichte kosten unnötig Zeit. +- Abrechnungen verzögern sich und belasten den Cashflow. +- Wissen über Kunden, Objekte und frühere Einsätze bleibt verteilt. +- Notdienste außerhalb der Bürozeiten werden uneinheitlich dokumentiert. + +Craftvia schließt diese Lücke mit einem durchgängigen, praxistauglichen Prozess. + +--- + +## 3. Markenstrategie + +### 3.1 Vision + +Handwerksbetriebe arbeiten ohne Medienbrüche: Jeder Auftrag ist klar, jeder Einsatz nachvollziehbar und jede erbrachte Leistung unmittelbar abrechenbar. + +### 3.2 Mission + +Craftvia verbindet Büro, Montageteams und Einsatzort in einem einfachen digitalen Arbeitsablauf. Die Plattform stellt relevante Informationen bereit, unterstützt die Dokumentation und überführt abgeschlossene Arbeit ohne Umwege in einen vollständigen Leistungsnachweis. + +### 3.3 Purpose + +Wir geben Handwerksbetrieben mehr Zeit für gute Arbeit und weniger Aufwand mit Papier, Rückfragen und Nachbearbeitung. + +### 3.4 Markenversprechen + +**Mit Craftvia wird aus einem Auftrag zuverlässig ein dokumentierter und abrechnungsfähiger Einsatz.** + +### 3.5 USP + +Craftvia bildet nicht nur einzelne Aufgaben ab, sondern verbindet den gesamten operativen Weg: + +> Auftrag übernehmen → Team vorbereiten → Einsatz dokumentieren → Leistung bestätigen → Backoffice informieren → schneller abrechnen + +Der Unterschied liegt in der Verbindung aus: + +- einem für Handwerksbetriebe verständlichen Prozess, +- mobiler, auch auf der Baustelle praktikabler Bedienung, +- vollständiger Objekt- und Einsatzhistorie, +- strukturierten Nachweisen für die Abrechnung, +- eigenständiger Notdienstdokumentation und +- dem KI-Assistenten **Lotse**, der Eingaben vereinfacht und Berichte vorbereitet. + +### 3.6 Markenwerte + +| Wert | Bedeutung für Craftvia | +|---|---| +| **Praktisch** | Funktionen lösen reale Aufgaben im Betriebsalltag. | +| **Verlässlich** | Informationen, Nachweise und Status sind nachvollziehbar verfügbar. | +| **Einfach** | Die Bedienung bleibt auch unter Zeitdruck klar. | +| **Verbindend** | Büro, Team und Einsatzort arbeiten mit demselben Informationsstand. | +| **Fortschrittlich** | Automatisierung und KI unterstützen konkret, ohne den Menschen zu verdrängen. | +| **Bodenständig** | Die Marke spricht verständlich, direkt und ohne Software-Pathos. | + +### 3.7 Markenpersönlichkeit + +Craftvia wirkt wie ein erfahrener, gut organisierter Kollege: ruhig, lösungsorientiert, aufmerksam und verbindlich. Die Marke kennt den Alltag auf der Baustelle ebenso wie die Anforderungen im Büro. Sie will nicht beeindrucken, sondern Arbeit spürbar leichter machen. + +**Craftvia ist:** kompetent, klar, robust, partnerschaftlich, modern. +**Craftvia ist nicht:** verspielt, technokratisch, belehrend, überladen oder künstlich futuristisch. + +--- + +## 4. Name und Markenidee + +### 4.1 Bedeutung des Namens + +**Craft** steht für Handwerk, Können und praktische Arbeit. **Via** bedeutet Weg oder „über/durch“ und verbindet Craftvia sprachlich mit Certvia und Visitvia. + +Die Markenidee lautet: + +> **Craftvia schafft den digitalen Weg vom Auftrag bis zur Abrechnung.** + +Der Name bleibt international anschlussfähig, während Sprache, Bildwelt und Kommunikation bewusst nah am deutschsprachigen Handwerk bleiben. + +### 4.2 Schreibweise + +- Immer **Craftvia**, mit großem C und ansonsten kleingeschrieben. +- Nicht: CraftVia, CRAFTVIA, Craft-via oder Craft Via. +- In Fließtext ohne Anführungszeichen verwenden. +- Generische Ergänzungen beschreibend anfügen, etwa „Craftvia Einsatzplanung“. + +### 4.3 Die Rolle des „Lotsen“ + +„Mein Lotse“ ist nicht länger die Produktmarke. **Lotse** kann als Name des KI-Assistenten innerhalb von Craftvia weiterleben. + +Der Lotse: + +- nimmt Sprach- und Texteingaben entgegen, +- strukturiert Notizen, Zeiten und Materialangaben, +- weist auf fehlende Dokumentation hin, +- bereitet Tages-, Montage- und Abschlussberichte vor, +- hilft beim Auffinden früherer Einsätze und Unterlagen, +- unterstützt, entscheidet aber nicht ungefragt anstelle des Nutzers. + +Bevorzugte Formulierungen: + +- „Frag den Lotsen.“ +- „Der Lotse unterstützt dich bei der Dokumentation.“ +- „Mit dem Lotsen zum vollständigen Einsatzbericht.“ + +Nicht verwenden: „Mein Lotse“ als parallelen Produktnamen oder eine eigenständige zweite Marke neben Craftvia. + +--- + +## 5. Positionierung + +### 5.1 Positionierungssatz + +Für Handwerks- und technische Servicebetriebe, die Aufträge zuverlässig zwischen Büro und Einsatzteam steuern wollen, ist Craftvia die digitale Einsatzplattform, die Informationen, Dokumentation und Abrechnungsvorbereitung in einem durchgängigen Prozess verbindet. Anders als isolierte Zeiterfassungs- oder Baustellendokumentationslösungen begleitet Craftvia den Auftrag von der Übernahme bis zum vollständigen Leistungsnachweis – praxistauglich, mobil und KI-gestützt. + +### 5.2 Zielgruppen + +**Primär** + +- Inhaber und Geschäftsführer kleiner und mittlerer Handwerksbetriebe +- Betriebs- und Einsatzleiter +- Backoffice, Disposition und vorbereitende Abrechnung +- Monteure, Techniker und Montageteams im Außeneinsatz + +**Sekundär** + +- Service- und Wartungsunternehmen +- Technischer Gebäudeservice und Facility Services +- Montage- und Instandhaltungsbetriebe +- Unternehmen mit wiederkehrenden Kunden- und Objekteinsätzen + +### 5.3 Nutzen nach Rolle + +| Rolle | Zentrales Bedürfnis | Nutzenversprechen | +|---|---|---| +| Geschäftsführung | Überblick und Liquidität | Schnellere Abrechnung, transparente Auftragsstände, weniger Verwaltungsaufwand | +| Backoffice | Vollständige Informationen | Strukturierte Nachweise ohne Zettelchaos und Nachtelefonieren | +| Einsatzleitung | Planbare Durchführung | Klare Zuweisungen, aktuelle Unterlagen und sichtbarer Fortschritt | +| Monteur/Techniker | Einfach arbeiten | Alle Informationen mobil, schnelle Erfassung und weniger Schreibarbeit | +| Kunde/Auftraggeber | Nachvollziehbare Leistung | Saubere Berichte, Fotos und Bestätigungen | + +### 5.4 Markennutzen + +**Funktional:** Aufträge, Teams, Zeiten, Material, Fotos, Dokumente und Berichte in einem Ablauf. +**Wirtschaftlich:** Leistungen früher und vollständiger abrechnen; Cashflow verbessern. +**Emotional:** Sicherheit, dass nichts verloren geht und der Betrieb unter Kontrolle bleibt. +**Sozial:** Professionelles Auftreten gegenüber Mitarbeitenden und Kunden. + +--- + +## 6. StoryBrand und Heldenreise + +### 6.1 Der Held + +Der Held ist nicht Craftvia, sondern der Handwerksbetrieb – konkret der Inhaber, die Einsatzleitung, das Backoffice und das Team vor Ort. + +### 6.2 Das Problem + +**Äußerlich:** Papierzettel, verstreute Informationen, fehlende Nachweise, langsame Berichte. +**Innerlich:** Frust über Rückfragen, Unsicherheit und das Gefühl, dem Tagesgeschäft hinterherzulaufen. +**Grundsätzlich:** Gute Arbeit sollte nicht an schlechter Informationsweitergabe und unnötiger Verwaltung verlieren. + +### 6.3 Der Begleiter + +Craftvia versteht beide Seiten des Betriebs: die Realität auf der Baustelle und die Anforderungen im Büro. Die Plattform gibt einen klaren Prozess vor, ohne unnötige Komplexität zu erzeugen. + +### 6.4 Der Plan + +1. Auftrag importieren oder anlegen. +2. Team zuweisen und alle Unterlagen bereitstellen. +3. Einsatz mobil dokumentieren und bestätigen. +4. Vollständigen Nachweis ans Backoffice übergeben. +5. Rechnung schneller erstellen. + +### 6.5 Call-to-Action + +**Primär:** „Craftvia kennenlernen“ oder „Demo vereinbaren“ +**Sekundär:** „Ablauf ansehen“ + +### 6.6 Erfolg + +- Aktuelle Informationen für alle Beteiligten +- Weniger Papier und doppelte Erfassung +- Vollständige Einsatzberichte +- Kürzere Zeit zwischen Leistung und Rechnung +- Besserer Cashflow +- Nachvollziehbare Kunden- und Objekthistorie + +### 6.7 Vermiedenes Scheitern + +- Stundenzettel bleiben nicht wochenlang im Fahrzeug. +- Das Backoffice wartet nicht auf fehlende Angaben. +- Abrechenbare Leistungen werden nicht vergessen. +- Bei Folgeeinsätzen muss Wissen nicht neu zusammengesucht werden. + +--- + +## 7. Botschaftensystem + +### 7.1 Kernbotschaft + +**Craftvia bringt Auftrag, Einsatz und Abrechnung auf einen gemeinsamen digitalen Weg.** + +### 7.2 Botschaftssäulen + +#### Alles für den Einsatz an einem Ort + +Aufträge, Ansprechpartner, Dokumente, technische Zeichnungen, Materialvorgaben und frühere Einsätze stehen dem Team zentral zur Verfügung. + +#### Dokumentieren, während die Arbeit passiert + +Zeiten, Material, Fotos, Notizen, Spracheingaben und Unterschriften werden direkt vor Ort erfasst – vollständig und nachvollziehbar. + +#### Schneller bereit zur Abrechnung + +Nach Abschluss erhält das Backoffice einen strukturierten Leistungsnachweis. Aus Wochen werden Tage, im Idealfall Stunden. + +#### Wissen bleibt im Betrieb + +Jeder Einsatz erweitert die Kunden- und Objekthistorie. Beim nächsten Auftrag sind relevante Informationen sofort verfügbar. + +#### KI, die konkret unterstützt + +Der Lotse strukturiert Eingaben, erkennt Lücken und bereitet Berichte vor. Die Kontrolle bleibt beim Menschen. + +### 7.3 Proof Points + +Kommunikation soll Nutzen möglichst mit überprüfbaren Funktionen belegen: + +- Auftragsimport aus vorhandenen Dokumenten +- Teamzuweisung und mobile Bereitstellung +- Zeit-, Material-, Foto- und Spracherfassung +- Pflichtnachweise und Vollständigkeitsprüfung +- Kundenunterschrift und Abschlussbericht +- automatische Information an das Backoffice +- Notdienstauftrag durch das Einsatzteam +- Kunden-, Objekt- und Einsatzhistorie +- PWA für Desktop, Tablet und Smartphone +- mandantenfähige Plattform für mehrere Betriebe + +Keine unbewiesenen Prozent- oder Zeitersparnisse kommunizieren. Quantitative Aussagen erst nach belastbaren Kundendaten verwenden. + +--- + +## 8. Claims und Taglines + +### 8.1 Claim-Hierarchie + +**Leitclaim** +> **Handwerk. Digital auf Kurs.** + +**Funktionsclaim** +> **Vom Auftrag bis zur Abrechnung.** + +**Nutzenclaim** +> **Sauber dokumentiert. Schneller abgerechnet.** + +**Kategorie-Descriptor** +> **Die Einsatzplattform fürs Handwerk.** + +### 8.2 Weitere freigegebene Aussagen + +- Weniger Papier. Mehr Überblick. +- Damit gute Arbeit schneller zur Rechnung wird. +- Büro und Baustelle. Endlich im selben Ablauf. +- Jeder Einsatz vollständig dokumentiert. +- Alle Informationen. Direkt am Einsatzort. +- Arbeit erledigt. Nachweis komplett. +- Vom ersten Auftrag bis zum nächsten Einsatz. +- Ihr digitaler Weg durch Auftrag, Einsatz und Nachweis. + +### 8.3 Claim-Verwendung + +- Der Leitclaim trägt Image- und Markenkommunikation. +- Der Funktionsclaim erklärt Craftvia bei Erstkontakt. +- Der Nutzenclaim eignet sich für Kampagnen und konkrete Landingpages. +- Den „Kurs“-Gedanken dosiert einsetzen; Craftvia ist keine maritime Themenwelt. + +--- + +## 9. Tonalität und Sprache + +### 9.1 Sprachprinzipien + +1. **Direkt:** Kurze Sätze, aktive Verben, klarer Nutzen. +2. **Bodenständig:** Alltagssprache statt Beratungsvokabular. +3. **Respektvoll:** Nutzer sind Fachleute ihres Handwerks. +4. **Konkret:** Reale Abläufe und Ergebnisse statt leerer Versprechen. +5. **Zuversichtlich:** Probleme benennen, aber lösungsorientiert bleiben. + +### 9.2 Anrede + +Für Website und Vertrieb wird zunächst die respektvolle **Sie-Ansprache** empfohlen. Im Produkt kann eine knappe, handlungsnahe Ansprache ohne Pronomen dominieren („Foto hinzufügen“, „Einsatz abschließen“). Der Lotse kann je nach Unternehmenseinstellung „Sie“ oder „du“ verwenden; innerhalb eines Mandanten muss dies konsistent sein. + +### 9.3 Bevorzugte Begriffe + +| Verwenden | Vermeiden | +|---|---| +| Auftrag, Einsatz, Team, Nachweis | Ticket, Workforce Unit, Case | +| Büro, Backoffice | Administration Layer | +| vor Ort | Field Environment | +| Bericht vorbereiten | Content generieren | +| unterstützt durch KI | revolutioniert durch AI | +| vollständig, nachvollziehbar | disruptiv, bahnbrechend | + +### 9.4 Beispiel + +**Gut:** „Der Einsatz ist abgeschlossen. Zeiten, Material, Fotos und Unterschrift liegen dem Büro sofort vor.“ +**Nicht gut:** „Unsere innovative End-to-End-AI-Plattform optimiert Ihre Field-Service-Prozesse.“ + +--- + +## 10. Markenarchitektur + +### 10.1 Empfohlenes Modell + +Die Produkte treten als **verbundene Einzelmarken** mit einheitlicher Namenslogik auf. Eine gemeinsame Absendermarke kann ergänzt werden, sobald sie definiert ist. + +| Produkt | Kernbereich | Descriptor | +|---|---|---| +| **Certvia** | Informationssicherheit | ISMS & Compliance | +| **Visitvia** | Besuchermanagement | Visitor Management | +| **Craftvia** | Handwerk und technischer Service | Work Order & Field Service Management | + +### 10.2 Gemeinsame Familienmerkmale + +- Namen folgen dem Muster **[Domäne] + via**. +- „via“ steht für einen klaren digitalen Weg durch einen Geschäftsprozess. +- Wortmarken teilen typografische Grundlogik, Proportionen und Qualitätsniveau. +- Jedes Produkt erhält eine eigene Akzentfarbe und ein eigenes Symbol. +- Struktur, Navigation und zentrale UI-Muster bleiben produktübergreifend verwandt. +- Die Familie verspricht verständliche, sichere und praxistaugliche Geschäftsanwendungen. + +### 10.3 Produkt- und Funktionsnamen in Craftvia + +Empfohlene beschreibende Module: + +- Craftvia Aufträge +- Craftvia Einsätze +- Craftvia Teams +- Craftvia Berichte +- Craftvia Objekte +- Craftvia Notdienst +- Craftvia Dokumente +- Craftvia Lotse + +Keine neue Untermarke für jede Funktion schaffen. **Lotse** ist die einzige bewusst personifizierte Produktfunktion. + +### 10.4 Cross-Product-Kommunikation + +Beispiel: + +> Drei klare Wege für zentrale Geschäftsprozesse: Certvia für Informationssicherheit, Visitvia für Besuchermanagement und Craftvia für Aufträge und Einsätze. + +Die Produkte nicht künstlich funktional koppeln, solange keine echte Integration besteht. + +--- + +## 11. Visuelle Identität + +![Craftvia Logo-, Farb- und Markenidentität](assets/craftvia-brand-identity-v1.png) + +Die oben gezeigte Identität überträgt die erkennbare dunkelblau-orange Gestaltung von „Mein Lotse“ auf Craftvia. Sie dient als verbindliche visuelle Vorzugsrichtung für die weitere Reinzeichnung. Das Hauptlogo gehört Craftvia; die illustrierte Lotsenfigur bleibt als eigenständiger KI-Assistent im Produkt erhalten. + +### 11.1 Gestaltungsprinzip + +Die visuelle Identität verbindet **handwerkliche Robustheit** mit **digitaler Klarheit**. Sie wirkt professionell und belastbar, nicht verspielt oder wie ein kurzlebiges Technologie-Startup. + +Leitbegriffe: + +- klare Wege +- verlässliche Verbindung +- Fortschritt +- Präzision +- Arbeit in Bewegung +- dokumentierter Abschluss + +### 11.2 Logo-Konzept + +Empfohlen wird eine reduzierte Wort-Bild-Marke aus: + +- der Wortmarke **Craftvia** und +- einem geometrischen Signet, das Weg, Verbindung und Abschluss abstrahiert. + +Geeignete Bildideen: + +1. **C-Pfad:** Ein stilisiertes C bildet einen Weg mit Start- und Zielpunkt. +2. **CV-Monogramm:** C und V greifen ineinander; das V wirkt zugleich wie Haken oder bestätigter Arbeitsschritt. +3. **Verbundene Wegpunkte:** Zwei bis drei Punkte bilden einen klaren Prozesspfad. + +**Vorzugsrichtung:** C-Pfad mit subtil integriertem Bestätigungshaken. Das Symbol verbindet Name, Prozess und Ergebnis, ohne auf austauschbare Hammer-, Zahnrad- oder Baustellenklischees zurückzugreifen. + +Der frühere maritime Lotse oder Kompass soll nicht mehr das Hauptlogo bestimmen. Ein diskreter Navigationsgedanke darf im Symbol oder in der Illustration des KI-Assistenten vorkommen. + +### 11.3 Logo-Regeln + +- Primär horizontale Wort-Bild-Marke verwenden. +- Signet allein nur bei kleinen Formaten, App-Icon und Favicon. +- Schutzraum mindestens in Höhe des kleinen „a“ der Wortmarke. +- Mindestbreite digital: 120 px für die vollständige Marke, 24 px für das Signet. +- Keine Schatten, Verläufe, Konturen oder Verzerrungen im Logo. +- Keine Platzierung auf unruhigen Fotos ohne ruhige Farbfläche. +- Einfarbige Varianten in Dunkelblau, Weiß und Schwarz vorsehen. + +### 11.4 Farbpalette + +#### Craftvia Kernfarben + +| Rolle | Name | Hex | Verwendung | +|---|---|---:|---| +| Primär | **Lotsenblau** | `#082E5B` | Logo, Navigation, Headlines, Vertrauen | +| Sekundär | **Signalorange** | `#FF6A00` | „via“, Weg-/Haken-Signet, CTA, aktive Elemente | +| Dunkel | **Graphit** | `#34383D` | Fließtext, Footer und starke Kontraste | +| Hell | **Hafengrau** | `#F3F5F7` | Flächen und Seitenhintergrund | +| Neutral | **Stahlgrau** | `#66727D` | Sekundärtext und Icons | +| Linie | **Zink** | `#D9E0E5` | Trennlinien und Eingabefelder | +| Weiß | **Klarweiß** | `#FFFFFF` | Karten und Kontrastflächen | + +#### Funktionsfarben + +| Funktion | Hex | Verwendung | +|---|---:|---| +| Erfolg | `#23845D` | abgeschlossen, geprüft | +| Warnung | `#C87912` | unvollständig, Aufmerksamkeit | +| Fehler | `#C64242` | Fehler, blockierende Aktion | +| Information | `#2F6FA3` | neutrale Hinweise | + +Farbe nie als einziges Statussignal einsetzen; immer mit Text und/oder Icon kombinieren. + +#### Produktfamilie + +Lotsenblau kann als gemeinsames neutrales Fundament der Produktfamilie dienen. Signalorange ist der exklusive Craftvia-Akzent. Certvia und Visitvia behalten beziehungsweise erhalten klar unterscheidbare Akzentfarben. Die konkrete Familienpalette ist in einem übergeordneten Designsystem abschließend zu harmonisieren. + +### 11.5 Typografie + +**Primärschrift:** **Inter** – für Web, App und Präsentationen. +**Fallback:** system-ui, Segoe UI, Roboto, Arial, sans-serif. + +Empfohlene Gewichte: + +- Headlines: 700 +- Zwischenüberschriften: 600 +- Fließtext: 400 +- UI-Labels und Buttons: 600 + +Grundregeln: + +- Satzfall statt Versalien verwenden. +- Fließtext digital mindestens 16 px. +- Großzügige Zeilenhöhe von etwa 1,5. +- Textzeilen auf Website-Inhalten auf ca. 65–75 Zeichen begrenzen. +- Zahlen und Statuswerte klar, aber nicht dekorativ hervorheben. + +### 11.6 Iconografie + +- Einfache Outline-Icons mit konsistenter Strichstärke. +- Abgerundete Ecken vermitteln Zugänglichkeit, ohne weich zu wirken. +- Icons immer aus der Tätigkeit ableiten: Auftrag, Kalender, Team, Kamera, Material, Bericht, Unterschrift. +- Keine Mischung verschiedener Icon-Stile. +- Maritime Symbole ausschließlich im Kontext des Lotsen und sehr sparsam einsetzen. + +### 11.7 Bildwelt + +Die Bildwelt zeigt echte Arbeitssituationen und den Informationsfluss zwischen Baustelle und Büro. + +**Motive** + +- Fachkräfte bei konkreter Arbeit, nicht beim Posieren +- Tablet oder Smartphone als selbstverständliches Werkzeug +- Details von Händen, Material, Anlage und Dokumentation +- Austausch zwischen Team und Backoffice +- saubere, glaubwürdige Arbeitsumgebungen mit realen Gebrauchsspuren + +**Stil** + +- dokumentarisch, hochwertig, natürlich +- neutrales bis leicht warmes Licht +- klare Bildkomposition und ausreichend Freiraum für Text +- diverse Gewerke, Altersgruppen und Personen zeigen + +**Vermeiden** + +- gestellte Handschlagmotive +- übertriebene Schutzhelm-Stockfotos ohne fachlichen Kontext +- reine Software-Screens auf abstrakten Neon-Hintergründen +- maritime Bildwelten, Leuchttürme oder Steuerräder als Dauermotiv + +### 11.8 Illustrationen + +Illustrationen dürfen Prozesse vereinfachen: Auftrag kommt herein, Team arbeitet, Nachweis geht zurück. Flache geometrische Formen, klare Linien und wenige Farben verwenden. Technische Details nur zeigen, wenn sie korrekt sind. + +--- + +## 12. UI- und UX-Grundsätze + +### 12.1 Leitprinzipien + +1. **Für den Einsatz gebaut:** große Touch-Ziele, hohe Kontraste, wenige Schritte. +2. **Status sofort sichtbar:** Was ist neu, offen, unvollständig oder abgeschlossen? +3. **Eine primäre Aktion je Ansicht:** Nutzer erkennen den nächsten Schritt ohne Suche. +4. **Fehler vermeiden:** Pflichtangaben und fehlende Nachweise früh anzeigen. +5. **Fortschritt sichern:** Eingaben zwischenspeichern und instabile Verbindung berücksichtigen. +6. **Rollen respektieren:** Monteur, Disposition und Backoffice sehen das für sie Relevante. + +### 12.2 Layout und Komponenten + +- 8-Pixel-Raster als Basis +- Karten für Aufträge und Einsätze mit klarer Statuskante +- Primärbuttons in Craft Orange auf ruhigen Flächen +- Sekundärbuttons als Outline oder Textbutton +- Eckenradius 8–12 px, nicht pillenförmig für jede Komponente +- Mindestgröße interaktiver Flächen: 44 × 44 px +- Formulare in logische, kurze Abschnitte teilen +- Fortschrittsanzeige bei mehrstufigem Einsatzabschluss + +### 12.3 Statussprache + +Bevorzugte Statuswerte: + +- Neu +- Geplant +- Unterwegs +- In Arbeit +- Dokumentation unvollständig +- Zur Prüfung +- Abgeschlossen +- Bereit zur Abrechnung +- Abgerechnet + +Status müssen tatsächliche Prozessschritte abbilden und dürfen nicht synonym verwendet werden. + +### 12.4 Lotse im Interface + +Der Lotse erscheint als hilfreiche, kontextbezogene Funktion – nicht als dauerhaft dominierender Chatbot. + +Beispiele: + +- „Bericht mit Lotse vorbereiten“ +- „3 Angaben fehlen. Lotse prüfen lassen“ +- „Sprachnotiz zusammenfassen“ + +Jede KI-Ausgabe bleibt prüf- und editierbar. Automatisch erzeugte Inhalte werden als Vorschlag gekennzeichnet. + +### 12.5 Barrierefreiheit + +- Ziel: WCAG 2.2 AA für Website und zentrale Produktabläufe +- Kontrast von Text und Interaktionen prüfen +- vollständige Tastaturbedienung im Backoffice +- sichtbare Fokuszustände +- verständliche Fehlermeldungen direkt am Feld +- Alternativtexte für inhaltliche Bilder +- keine Information ausschließlich durch Farbe oder Bewegung + +--- + +## 13. Homepage-Struktur + +### 13.1 Header + +**Navigation:** Produkt · Lösungen · Für wen · Lotse · Preise · Über uns +**Sekundäre Aktion:** Anmelden +**Primäre Aktion:** Demo vereinbaren + +### 13.2 Hero + +**Eyebrow:** Die Einsatzplattform fürs Handwerk +**Headline:** **Handwerk. Digital auf Kurs.** +**Subheadline:** Craftvia verbindet Büro und Baustelle – vom Auftrag über die mobile Dokumentation bis zum vollständigen Nachweis für eine schnellere Abrechnung. +**Primärer CTA:** Demo vereinbaren +**Sekundärer CTA:** Ablauf ansehen + +**Visual:** Ein realistischer Einsatzablauf mit mobiler Auftragsansicht im Vordergrund und einer klaren Statuskette im Hintergrund. Keine rein dekorative Geräte-Collage. + +### 13.3 Problemsektion + +**Headline:** **Gute Arbeit ist längst erledigt. Die Rechnung wartet noch.** + +Stundenzettel liegen im Fahrzeug, Fotos fehlen und Materialangaben kommen auf Zuruf. Das Backoffice sammelt Informationen, statt Rechnungen vorzubereiten. So vergehen zwischen Einsatz und Zahlung wertvolle Wochen. + +**Problemkarten:** + +- Zettel und Informationen sind unterwegs. +- Rückfragen kosten Büro und Team Zeit. +- Fehlende Nachweise verzögern die Abrechnung. + +### 13.4 Lösungssektion + +**Headline:** **Ein klarer Weg für jeden Auftrag.** + +1. **Auftrag vorbereiten** – Daten übernehmen, Unterlagen zuordnen, Team einplanen. +2. **Einsatz durchführen** – Alle Informationen mobil nutzen und Leistungen direkt erfassen. +3. **Vollständig abschließen** – Bericht, Fotos und Unterschrift prüfen und übergeben. +4. **Schneller abrechnen** – Das Backoffice erhält einen strukturierten Nachweis. + +### 13.5 Nutzen-/Cashflow-Sektion + +**Headline:** **Damit aus geleisteter Arbeit schneller Umsatz wird.** + +Craftvia verkürzt den Weg zwischen Baustelle und Büro. Sobald ein Einsatz abgeschlossen ist, liegen die relevanten Angaben strukturiert vor. Das reduziert Nacharbeit und schafft die Grundlage, Rechnungen früher zu stellen. + +**Hinweis:** Keine konkrete Beschleunigung in Prozent versprechen, bis diese durch Pilotkunden belegt ist. + +### 13.6 Zielgruppensektion + +**Für das Büro:** Überblick, vollständige Nachweise, weniger Nachtelefonieren. +**Für die Einsatzleitung:** klare Planung und aktueller Status. +**Für das Team vor Ort:** alle Unterlagen und einfache Dokumentation in einer Anwendung. +**Für die Geschäftsführung:** transparente Abläufe und schnellerer Cashflow. + +### 13.7 Lotse-Sektion + +**Headline:** **Der Lotse nimmt Schreibarbeit ab. Sie behalten die Kontrolle.** + +Sprachnotizen strukturieren, fehlende Angaben erkennen und Berichte vorbereiten: Der KI-Assistent unterstützt genau dort, wo Dokumentation im Alltag Zeit kostet. Alle Vorschläge bleiben prüfbar. + +**CTA:** Lotse kennenlernen + +### 13.8 Historie-Sektion + +**Headline:** **Beim nächsten Einsatz ist das Wissen schon da.** + +Vergangene Arbeiten, Berichte, Fotos, technische Zeichnungen und Hinweise bleiben am Kunden und Objekt verfügbar. So startet das Team nicht bei null. + +### 13.9 Notdienst-Sektion + +**Headline:** **Auch dann dokumentiert, wenn das Büro nicht besetzt ist.** + +Teams können einen Notdiensteinsatz selbst anlegen, Leistungen erfassen und abschließen. Das Backoffice erhält am nächsten Arbeitstag alle Angaben zur Prüfung und Abrechnung. + +### 13.10 Vertrauen und Produktfamilie + +**Headline:** **Ein Produkt aus einer klaren Softwarefamilie.** + +Craftvia folgt derselben Idee wie Certvia und Visitvia: komplexe Geschäftsprozesse verständlich führen, Informationen zentral verfügbar machen und tägliche Arbeit verlässlich dokumentieren. + +### 13.11 Abschluss-CTA + +**Headline:** **Bringen Sie Ihre Aufträge auf einen klaren digitalen Weg.** +**Text:** Erleben Sie, wie Craftvia Büro und Einsatzteam verbindet und abgeschlossene Arbeit schneller abrechnungsfähig macht. +**CTA:** Demo vereinbaren + +--- + +## 14. Mustertexte + +### 14.1 Kurzbeschreibung + +Craftvia ist die digitale Einsatzplattform für Handwerks- und Servicebetriebe. Sie verbindet Auftrag, Team, Baustellendokumentation und Abrechnungsvorbereitung in einem durchgängigen Ablauf. + +### 14.2 50-Wörter-Pitch + +Mit Craftvia erhalten Teams alle Auftragsinformationen direkt am Einsatzort, dokumentieren Zeiten, Material, Fotos und Leistungen mobil und übergeben vollständige Nachweise ans Büro. So sinkt der Abstimmungsaufwand, Wissen bleibt am Kunden und abgeschlossene Arbeit kann schneller abgerechnet werden – unterstützt durch den KI-Assistenten Lotse. + +### 14.3 Elevator Pitch + +Viele Handwerksbetriebe leisten heute gute Arbeit und warten trotzdem Wochen auf die nötigen Unterlagen für die Rechnung. Craftvia verbindet Büro und Baustelle in einem digitalen Prozess: Auftrag bereitstellen, Einsatz dokumentieren, Bericht abschließen und vollständig ans Backoffice übergeben. Damit wird aus erledigter Arbeit schneller eine abrechenbare Leistung. + +### 14.4 App-Store-/Verzeichnistext + +**Craftvia – Aufträge und Einsätze verwalten** + +Craftvia begleitet Handwerks- und Serviceteams vom Auftrag bis zum vollständigen Leistungsnachweis. Alle relevanten Informationen stehen mobil zur Verfügung. Zeiten, Material, Fotos, Notizen und Unterschriften werden direkt vor Ort erfasst. Das Backoffice erhält strukturierte Unterlagen für Prüfung und Abrechnung. + +### 14.5 Social-/Vertriebs-Teaser + +Der Auftrag ist erledigt – aber der Stundenzettel liegt noch im Fahrzeug? Craftvia bringt Büro und Baustelle in einen gemeinsamen Ablauf. Leistungen werden direkt vor Ort dokumentiert und vollständig zur Abrechnung übergeben. Weniger Nachfragen. Weniger Papier. Schneller bereit für die Rechnung. + +### 14.6 Produktfamilien-Pitch + +Certvia, Visitvia und Craftvia bilden eine Familie klarer Geschäftsanwendungen: Informationssicherheit verwalten, Besucherprozesse steuern und Handwerkseinsätze digital begleiten. Jede Lösung konzentriert sich auf einen zentralen Prozess – verständlich, nachvollziehbar und praxistauglich. + +--- + +## 15. Anwendungsszenarien + +### 15.1 Geplanter Auftrag + +Das Backoffice übernimmt Daten aus einer Auftragsbestätigung, prüft Kunde und Objekt, ergänzt Unterlagen und weist ein Team zu. Das Team sieht Auftrag, Ansprechpartner, Materialvorgaben und Zeichnungen mobil. Nach dem Einsatz werden Zeiten, Verbrauch, Fotos und Unterschrift abgeschlossen. Der Bericht steht unmittelbar zur Prüfung bereit. + +### 15.2 Wiederkehrender Einsatz + +Vor Ort öffnet der Techniker die Objekthistorie und sieht frühere Arbeiten, Bilder und Hinweise. Neue Erkenntnisse werden dem Objekt zugeordnet und stehen beim nächsten Einsatz wieder zur Verfügung. + +### 15.3 Notdienst + +Ein Monteur legt außerhalb der Bürozeiten selbst einen Notdiensteinsatz an, dokumentiert Problem, Maßnahmen, Material und Arbeitszeit und lässt die Leistung bestätigen. Das Backoffice wird informiert und kann den Vorgang am nächsten Arbeitstag abrechnen. + +### 15.4 KI-gestützte Dokumentation + +Der Monteur spricht eine Notiz ein. Der Lotse schlägt strukturierte Tätigkeiten und Berichtstext vor, erkennt fehlende Angaben und bittet um Ergänzung. Vor dem Abschluss prüft und bestätigt der Monteur das Ergebnis. + +--- + +## 16. Do & Don't + +### Do + +- Craftvia als Weg vom Auftrag zum Nachweis erklären. +- wirtschaftlichen Nutzen mit dem Arbeitsalltag verbinden. +- echte Gewerke und glaubwürdige Situationen zeigen. +- Softwarefunktionen in einfacher Sprache beschreiben. +- Lotse als unterstützende, kontrollierbare KI positionieren. +- Craftvia sichtbar in die Certvia-/Visitvia-Familie einordnen. + +### Don't + +- „Mein Lotse“ weiterhin als Produktname verwenden. +- eine maritime Erlebniswelt um Craftvia bauen. +- KI als Ersatz für Fachkräfte darstellen. +- unbelegte Effizienz- oder Umsatzversprechen machen. +- Craftvia auf reine Zeiterfassung reduzieren. +- mit ERP-Fachbegriffen kommunizieren, wenn Alltagssprache genügt. +- Certvia, Visitvia und Craftvia visuell völlig unabhängig entwickeln. + +--- + +## 17. Governance und nächste Schritte + +### 17.1 Verbindlich in dieser Version + +- Markenname und Schreibweise **Craftvia** +- Zugehörigkeit zur Produktfamilie Certvia / Visitvia +- Kernpositionierung und Markenversprechen +- Claim-Hierarchie +- Lotse als optionaler Name des KI-Assistenten +- Tonalitäts- und UX-Prinzipien +- strategische Richtung der visuellen Identität + +### 17.2 Vor Veröffentlichung zu validieren + +- Marken-, Domain- und Kollisionsprüfung für Craftvia +- finale Absendermarke beziehungsweise Herstellerzusatz +- Logoentwicklung und Prüfung in kleinen Größen +- Abstimmung der produktübergreifenden Farb- und Designsysteme +- Barrierefreiheitsprüfung der finalen Farbkombinationen +- Datenschutz- und Transparenztexte für KI-Funktionen +- quantitative Nutzenversprechen anhand von Pilotprojekten +- tschechische Namens-, Claim- und Sprachprüfung vor Lokalisierung + +### 17.3 Empfohlene Umsetzungsreihenfolge + +1. Wort-Bild-Marke und App-Icon ausarbeiten. +2. gemeinsames Designsystem für Certvia, Visitvia und Craftvia definieren. +3. zentrale Website-Ansichten gestalten und testen. +4. Kernabläufe der App prototypisch validieren. +5. Pilotkunden begleiten und Nutzenkennzahlen erheben. +6. Markenbotschaften mit echten Belegen schärfen. + +--- + +## 18. Markenkompass + +Bei jeder neuen Seite, Funktion oder Kampagne sind fünf Fragen zu beantworten: + +1. Hilft dies, den Weg vom Auftrag zur Abrechnung klarer zu machen? +2. Ist der Nutzen für Büro oder Einsatzteam sofort verständlich? +3. Wirkt die Lösung praktisch, verlässlich und bodenständig? +4. Fügt sie sich sichtbar in die Produktfamilie ein? +5. Unterstützt der Lotse den Menschen, ohne Kontrolle oder Transparenz zu nehmen? + +Wenn eine Maßnahme diese Fragen nicht überzeugend beantwortet, sollte sie überarbeitet werden. + +--- + +**Craftvia** +**Handwerk. Digital auf Kurs.** +*Vom Auftrag bis zur Abrechnung.* diff --git a/docs/craftvia/SPEC-CRAFTVIA.md b/docs/craftvia/SPEC-CRAFTVIA.md new file mode 100644 index 0000000..bdfd103 --- /dev/null +++ b/docs/craftvia/SPEC-CRAFTVIA.md @@ -0,0 +1,2480 @@ +# Technische Spezifikation – Handwerker- und Montageeinsatz-App + +**Dokumenttyp:** Software Design Specification / Technisches Umsetzungskonzept +**Zielgruppe:** Codex, Claude Code, Softwareentwickler und technische Projektleitung +**Status:** Entwurf für MVP +**Version:** 1.0 +**Sprache:** Deutsch + +--- + +## 1. Zielsetzung + +Ziel ist die Entwicklung einer mandantenfähigen Webanwendung für Handwerks- und Montagebetriebe. + +Die Anwendung soll den vollständigen Ablauf eines Kunden- oder Baustelleneinsatzes digital unterstützen: + +1. Auftragsbestätigung oder Einsatzdokument importieren +2. Auftragsdaten automatisch erkennen +3. Auftrag prüfen und einem Montageteam zuweisen +4. Auftrag auf Tablet oder Smartphone bearbeiten +5. Leistungen, Arbeitszeiten, Material, Fotos und Notizen dokumentieren +6. Tagesbericht oder Abschlussbericht erzeugen +7. Auftrag an das Backoffice zur Abrechnung übergeben +8. Einsatzhistorie je Kunde und Objekt dauerhaft verfügbar halten + +Für den MVP wird keine native iOS- oder Android-App entwickelt. Die Lösung wird als responsive Progressive Web App, kurz PWA, umgesetzt. + +--- + +## 2. Produktvision + +Die Anwendung soll keine vollständige ERP-, Buchhaltungs- oder Warenwirtschaftslösung ersetzen. + +Sie bildet die operative Verbindung zwischen: + +- Backoffice +- Montageteams +- Kunden +- Baustellen +- Objekten +- Auftragsdokumenten +- Einsatzdokumentation +- Abrechnungsvorbereitung + +Das System soll modular aufgebaut werden, sodass später weitere Funktionen und Schnittstellen ergänzt werden können. + +Mögliche spätere Erweiterungen: + +- direkte ERP- und Buchhaltungsschnittstellen +- digitale Zeiterfassung +- Lager- und Bestandsverwaltung +- Artikelstammdaten +- Anlagen- und Geräteverwaltung +- Wartungsintervalle +- Angebots- und Rechnungsstellung +- Kundenportal +- Tourenplanung +- Kalenderintegration +- automatische Einsatzplanung +- KI-Assistent für Monteure und Backoffice + +--- + +## 3. Grundlegende Architekturentscheidung + +### 3.1 Anwendungstyp + +Der MVP wird als responsive Webanwendung mit PWA-Funktionen umgesetzt. + +Die Anwendung muss auf folgenden Geräten nutzbar sein: + +- Desktop-PC +- Notebook +- iPad +- Android-Tablet +- iPhone +- Android-Smartphone + +### 3.2 Vorteile der PWA + +- keine separate Entwicklung für iOS und Android +- Installation auf dem Startbildschirm möglich +- Nutzung der Gerätekamera +- Nutzung des Mikrofons +- lokale Zwischenspeicherung +- eingeschränkte Offline-Fähigkeit +- zentrale Bereitstellung von Updates +- geringerer Entwicklungs- und Wartungsaufwand + +### 3.3 Mandantenfähigkeit + +Die Anwendung muss von Beginn an vollständig mandantenfähig aufgebaut werden. + +Jeder Handwerksbetrieb stellt einen eigenen Mandanten dar. + +Mandanten dürfen ausschließlich auf ihre eigenen Daten zugreifen. + +Eine Vermischung von Daten verschiedener Mandanten muss technisch ausgeschlossen werden. + +--- + +## 4. Rollenmodell + +### 4.1 Plattformadministrator + +Der Plattformadministrator verwaltet die gesamte SaaS-Plattform. + +Berechtigungen: + +- Mandanten anlegen +- Mandanten deaktivieren +- Mandantenadministratoren anlegen +- Systemstatus einsehen +- globale Systemeinstellungen verwalten +- Funktionsmodule je Mandant aktivieren +- Speicherverbrauch und Nutzung einsehen +- Supportzugriff nach expliziter Freigabe durchführen + +Der Plattformadministrator soll nicht standardmäßig auf fachliche Mandantendaten zugreifen können. + +--- + +### 4.2 Mandantenadministrator + +Der Mandantenadministrator verwaltet die Organisation eines Kunden. + +Berechtigungen: + +- Benutzer anlegen +- Benutzer deaktivieren +- Rollen vergeben +- Montageteams anlegen +- Mitarbeiter Teams zuordnen +- Kunden verwalten +- Objekte verwalten +- Vorlagen verwalten +- Auftragsstatus konfigurieren +- E-Mail-Empfänger konfigurieren +- Unternehmensdaten verwalten +- Berichtsvorlagen verwalten +- Nummernkreise konfigurieren + +--- + +### 4.3 Backoffice + +Das Backoffice plant, verwaltet und kontrolliert Aufträge. + +Berechtigungen: + +- Auftragsdokumente importieren +- erkannte Daten prüfen +- Kunden und Objekte anlegen +- Aufträge erstellen +- Aufträge bearbeiten +- Montageteams zuweisen +- Dokumente und technische Zeichnungen hinterlegen +- Auftragsfortschritt einsehen +- Berichte prüfen +- Aufträge zur Abrechnung freigeben +- Einsatzhistorie einsehen +- Notdiensteinsätze nachbearbeiten + +--- + +### 4.4 Monteur + +Der Monteur bearbeitet zugewiesene Aufträge. + +Berechtigungen: + +- eigene und dem Team zugewiesene Aufträge einsehen +- Auftragsinformationen anzeigen +- Kundendaten und Objektinformationen anzeigen +- technische Dokumente und Zeichnungen anzeigen +- Einsatz starten und beenden +- Arbeitszeiten dokumentieren +- Material dokumentieren +- Fotos aufnehmen +- Notizen erfassen +- Sprachnotizen aufnehmen +- Tagesberichte erstellen +- Abschlussberichte erstellen +- Kundenunterschrift erfassen +- Notdiensteinsatz anlegen +- vorherige freigegebene Einsätze am Objekt einsehen + +Ein Monteur darf keine Aufträge oder Kundendaten anderer Teams einsehen, sofern ihm hierzu keine zusätzliche Berechtigung erteilt wurde. + +--- + +### 4.5 Teamleiter + +Der Teamleiter besitzt die Rechte eines Monteurs und zusätzlich: + +- Teamaufträge einsehen +- Aufträge innerhalb des Teams koordinieren +- Tagesberichte prüfen +- Abschlussberichte freigeben +- Teammitglieder einem Einsatz zuordnen +- Korrekturen vor Abschluss anfordern + +--- + +## 5. Mandantenmodell + +Jeder Datensatz muss eindeutig einem Mandanten zugeordnet sein. + +Dies betrifft insbesondere: + +- Benutzer +- Rollen +- Teams +- Kunden +- Ansprechpartner +- Objekte +- Aufträge +- Einsätze +- Berichte +- Dokumente +- Fotos +- Materialien +- Benachrichtigungen +- Audit-Logs +- Vorlagen + +### 5.1 Technische Anforderung + +Jede relevante Datenbanktabelle erhält ein Feld: + +```text +tenant_id +``` + +Der Zugriff auf Daten muss serverseitig immer über den aktuellen Mandantenkontext eingeschränkt werden. + +Eine reine Filterung im Frontend ist nicht ausreichend. + +### 5.2 Empfohlene Umsetzung + +Für den MVP kann eine gemeinsame Datenbank mit mandantenbezogener Datenisolation verwendet werden. + +Empfehlung: + +- PostgreSQL +- Row-Level Security oder zentraler Repository-Filter +- tenant_id in allen fachlichen Tabellen +- serverseitige Autorisierungsprüfung bei jedem Zugriff +- getrennte Dateipfade oder Buckets je Mandant + +Später kann optional ein Datenbank-pro-Mandant-Modell ergänzt werden. + +--- + +## 6. Kernmodule des MVP + +Der MVP besteht aus folgenden Modulen: + +1. Benutzer- und Rollenverwaltung +2. Mandantenverwaltung +3. Kundenverwaltung +4. Objektverwaltung +5. Teamverwaltung +6. Auftragsimport +7. Auftragsverwaltung +8. Einsatzbearbeitung +9. Materialdokumentation +10. Foto- und Dokumentenverwaltung +11. Tages- und Abschlussberichte +12. Notdiensteinsätze +13. Objekt- und Einsatzhistorie +14. Benachrichtigungen +15. Audit-Logging +16. PWA- und Offline-Funktionen + +--- + +## 7. Kundenverwaltung + +### 7.1 Kundendaten + +Folgende Daten sollen verwaltet werden: + +- Kundennummer +- Firmenname +- Anrede +- Vorname +- Nachname +- Straße +- Hausnummer +- Postleitzahl +- Ort +- Land +- Telefonnummer +- Mobilnummer +- E-Mail-Adresse +- allgemeine Hinweise +- Abrechnungshinweise +- Status +- Erstellungsdatum +- Änderungsdatum + +### 7.2 Ansprechpartner + +Ein Kunde kann mehrere Ansprechpartner besitzen. + +Daten: + +- Name +- Funktion +- Telefonnummer +- Mobilnummer +- E-Mail-Adresse +- bevorzugter Kontaktweg +- Bemerkungen + +### 7.3 Dublettenprüfung + +Beim Import eines Auftrags muss geprüft werden, ob der Kunde bereits existiert. + +Mögliche Vergleichswerte: + +- Kundennummer +- Firmenname +- Adresse +- E-Mail-Adresse +- Telefonnummer + +Bei unsicherer Übereinstimmung muss das Backoffice entscheiden: + +- bestehenden Kunden verwenden +- neuen Kunden anlegen +- Datensätze zusammenführen + +Eine automatische Zusammenführung darf im MVP nicht ohne Bestätigung erfolgen. + +--- + +## 8. Objektverwaltung + +Ein Kunde kann mehrere Objekte besitzen. + +Beispiele: + +- Baustelle +- Filiale +- Wohnhaus +- Produktionsstandort +- Bürogebäude +- technische Anlage +- Wartungsstandort + +### 8.1 Objektdaten + +- Objektbezeichnung +- Kunde +- Straße +- Hausnummer +- Postleitzahl +- Ort +- Land +- Ansprechpartner vor Ort +- Telefonnummer +- Zugangshinweise +- Parkhinweise +- Sicherheitsinformationen +- allgemeine technische Hinweise +- Status +- geografische Koordinaten optional + +### 8.2 Objektbezogene Dokumente + +Pro Objekt können Dokumente hinterlegt werden: + +- technische Zeichnungen +- Grundrisse +- Schaltpläne +- Montageanleitungen +- Sicherheitsunterlagen +- Produktunterlagen +- Kundenhinweise +- Fotos vorheriger Einsätze +- sonstige PDF-Dateien + +### 8.3 Objekt-Historie + +Die Anwendung muss pro Objekt eine chronologische Einsatzhistorie anzeigen. + +Anzuzeigen sind: + +- Datum +- Auftrag +- Einsatzart +- eingesetztes Team +- durchgeführte Arbeiten +- verwendetes Material +- Fotos +- Berichte +- besondere Hinweise +- Kundenunterschrift +- Status +- offene Folgearbeiten + +Für den MVP ist keine vollständige Geräte-, Anlagen- oder Seriennummernverwaltung erforderlich. + +--- + +## 9. Auftragsimport per PDF + +### 9.1 Ziel + +Das Backoffice soll Auftragsdaten nicht vollständig manuell erfassen müssen. + +Eine Auftragsbestätigung oder ein vergleichbares PDF-Dokument wird in die Anwendung hochgeladen. + +Das System extrahiert daraus möglichst viele relevante Daten und erstellt einen Auftragsentwurf. + +### 9.2 Unterstützte Dateien + +MVP: + +- PDF mit eingebettetem Text +- gescannte PDF-Dateien +- optional Bilddateien wie JPG und PNG + +### 9.3 Verarbeitung + +Der Importprozess besteht aus: + +1. Datei hochladen +2. Malware- und Dateitypprüfung +3. Texterkennung +4. Dokumentenanalyse +5. strukturierte Datenextraktion +6. Plausibilitätsprüfung +7. Dublettenprüfung +8. Anzeige einer Prüfmaske +9. Bestätigung durch das Backoffice +10. Erstellung oder Zuordnung von Kunde, Objekt und Auftrag + +### 9.4 OCR und KI-Extraktion + +Für gescannte Dokumente wird OCR eingesetzt. + +Für die strukturierte Extraktion kann ein KI-Modell verwendet werden. + +Zu extrahierende Felder: + +- Auftragsnummer +- Angebotsnummer +- Kundennummer +- Firmenname +- Kundenadresse +- Objektadresse +- Ansprechpartner +- Telefonnummer +- E-Mail-Adresse +- Auftragsdatum +- geplanter Ausführungszeitraum +- Leistungsbeschreibung +- Positionen +- Mengen +- Materialinformationen +- besondere Hinweise +- Gesamtbetrag optional +- Referenzen +- Dokumentdatum + +### 9.5 Vertrauenswerte + +Für jedes erkannte Feld soll ein Vertrauenswert gespeichert werden. + +Beispiel: + +```json +{ + "field": "customer_name", + "value": "Musterbau GmbH", + "confidence": 0.96 +} +``` + +Unsichere Felder müssen in der Prüfmaske hervorgehoben werden. + +### 9.6 Manuelle Prüfung + +Ein importierter Auftrag darf nicht automatisch produktiv freigegeben werden. + +Status nach Import: + +```text +Entwurf – Prüfung erforderlich +``` + +Das Backoffice muss die erkannten Daten bestätigen oder korrigieren. + +### 9.7 Originaldokument + +Das Originaldokument wird dauerhaft am Auftrag gespeichert. + +Zusätzlich werden gespeichert: + +- Importdatum +- importierender Benutzer +- erkannter Text +- strukturierte Extraktion +- Extraktionsversion +- verwendetes Extraktionsmodell +- Korrekturen des Benutzers + +--- + +## 10. Auftragsverwaltung + +### 10.1 Auftragsdaten + +- interne Auftrags-ID +- externe Auftragsnummer +- Mandant +- Kunde +- Objekt +- Ansprechpartner +- Auftragsart +- Priorität +- Status +- Beschreibung +- Leistungsumfang +- geplantes Datum +- geplanter Zeitraum +- zugewiesenes Team +- zuständiger Teamleiter +- Dokumente +- Materialvorgabe +- Pflichtfotos +- Pflichtfelder +- Unterschrift erforderlich +- Abrechnungsart +- interne Hinweise +- Hinweise für Monteure +- Erstellungsdatum +- Änderungsdatum + +### 10.2 Auftragsarten + +Beispiele: + +- Montage +- Reparatur +- Wartung +- Störung +- Notdienst +- Besichtigung +- Abnahme +- Nacharbeit + +Die Auftragsarten sollen je Mandant konfigurierbar sein. + +### 10.3 Statusmodell + +Empfohlene Statuswerte: + +```text +Entwurf +Prüfung erforderlich +Geplant +Zugewiesen +Angenommen +In Anfahrt +In Bearbeitung +Pausiert +Wartet auf Material +Tagesbericht erstellt +Technisch abgeschlossen +Unterschrift ausstehend +Zur Prüfung +Zur Abrechnung freigegeben +Abgerechnet +Storniert +``` + +Statusübergänge müssen serverseitig geprüft werden. + +### 10.4 Teamzuweisung + +Ein Auftrag kann einem Montageteam zugewiesen werden. + +Optional können zusätzlich einzelne Mitarbeiter ausgewählt werden. + +Ein Team erhält nach Zuweisung eine Benachrichtigung. + +--- + +## 11. Montageteams + +### 11.1 Teamdaten + +- Teamname +- Teamleiter +- Mitglieder +- Status +- Telefonnummer +- Fahrzeug optional +- Einsatzgebiet optional +- interne Hinweise + +### 11.2 Auftragsansicht + +Monteure sehen: + +- heutige Aufträge +- kommende Aufträge +- laufende Aufträge +- pausierte Aufträge +- abzuschließende Aufträge +- vergangene eigene Aufträge + +Darstellung als: + +- Listenansicht +- Kalenderansicht optional +- Kartenansicht erst nach dem MVP + +--- + +## 12. Einsatzbearbeitung durch Monteure + +### 12.1 Einsatzstart + +Beim Start eines Einsatzes werden gespeichert: + +- Startzeit +- Benutzer +- Team +- Auftrag +- optional Standort +- Gerätestatus +- Online- oder Offline-Status + +Optional kann ein Status „In Anfahrt“ vor dem eigentlichen Arbeitsbeginn gesetzt werden. + +### 12.2 Arbeitszeiten + +Ein Einsatz kann mehrere Zeitabschnitte besitzen. + +Beispiele: + +- Anfahrt +- Arbeitszeit +- Pause +- Materialbeschaffung +- Rückfahrt +- Unterbrechung + +Für den MVP genügt eine einfache Start-, Pause- und Stopp-Funktion. + +Manuelle Korrekturen müssen protokolliert werden. + +### 12.3 Tätigkeitsdokumentation + +Monteure können dokumentieren: + +- durchgeführte Arbeiten +- Abweichungen vom Auftrag +- Probleme +- zusätzliche Leistungen +- nicht ausführbare Arbeiten +- erforderliche Folgearbeiten +- Empfehlungen +- Kundenhinweise + +Eingabemöglichkeiten: + +- Text +- strukturierte Auswahlfelder +- Sprachnotiz +- Foto + +### 12.4 Checklisten + +Ein Auftrag kann eine Checkliste enthalten. + +Beispiele: + +- Anlage spannungsfrei geschaltet +- Arbeitsbereich abgesichert +- Material geprüft +- Funktionsprüfung durchgeführt +- Arbeitsbereich gereinigt +- Kunde eingewiesen +- Pflichtfotos erstellt + +Checklisten können je Auftragsart als Vorlage definiert werden. + +--- + +## 13. Materialdokumentation + +### 13.1 Materialvorgabe + +Das Backoffice kann geplantes Material am Auftrag hinterlegen. + +Felder: + +- Bezeichnung +- Artikelnummer optional +- geplante Menge +- Einheit +- Bemerkung + +### 13.2 Tatsächlich verwendetes Material + +Der Monteur bestätigt oder ändert je Position: + +- vollständig verwendet +- teilweise verwendet +- nicht verwendet +- zusätzlich verwendet + +Zu erfassen: + +- tatsächliche Menge +- Einheit +- Begründung bei Abweichung +- Foto optional +- Notiz optional + +### 13.3 Zusatzmaterial + +Monteure können nicht geplantes Material ergänzen. + +Felder: + +- Bezeichnung +- Artikelnummer optional +- Menge +- Einheit +- Grund +- Foto optional + +### 13.4 MVP-Abgrenzung + +Im MVP erfolgt keine automatische Lagerbuchung. + +Die Materialdokumentation dient: + +- dem Arbeitsnachweis +- der Abrechnungsvorbereitung +- der Nachkalkulation +- der Information des Backoffice + +--- + +## 14. Foto- und Dateidokumentation + +### 14.1 Fotofunktionen + +Monteure können Fotos: + +- direkt mit der Kamera aufnehmen +- aus der Galerie auswählen +- einem Auftrag zuordnen +- einer Checklistenposition zuordnen +- als Vorher-, Während- oder Nachher-Foto kennzeichnen +- mit Kommentar versehen + +### 14.2 Pflichtfotos + +Das Backoffice kann Pflichtfotos definieren. + +Beispiele: + +- Ausgangszustand +- Typenschild +- Leitungsverlauf +- Zwischenschritt +- fertige Montage +- Funktionsprüfung +- Arbeitsbereich nach Abschluss + +Ein Auftrag kann nicht abgeschlossen werden, wenn verpflichtende Fotos fehlen. + +### 14.3 Metadaten + +Zu jedem Foto werden gespeichert: + +- Auftrag +- Einsatz +- Benutzer +- Zeitstempel +- Kategorie +- Kommentar +- Dateigröße +- MIME-Type +- optional Standort +- Uploadstatus +- Prüfsumme + +### 14.4 Bildoptimierung + +Bilder sollen vor dem Upload komprimiert werden. + +Das Original kann optional erhalten bleiben. + +Empfehlung: + +- Vorschaubild +- optimierte Arbeitskopie +- optional Originaldatei + +--- + +## 15. Sprachaufnahmen und KI-Unterstützung + +### 15.1 Sprachnotizen + +Monteure können Sprachnotizen aufnehmen. + +Das System speichert: + +- Audiodatei +- Transkription +- Zeitstempel +- Benutzer +- Bezug zum Auftrag oder Einsatz + +### 15.2 KI-Verarbeitung + +Die KI kann aus den vorhandenen Informationen einen Berichtsentwurf erstellen. + +Datenquellen: + +- Auftragsbeschreibung +- Tätigkeitsnotizen +- Sprachnotizen +- Checklisten +- Materialabweichungen +- Fotos und Bildkommentare +- Arbeitszeiten +- offene Folgearbeiten + +### 15.3 Freigabeprinzip + +KI-generierte Inhalte dürfen nicht automatisch als endgültiger Bericht versendet werden. + +Der Monteur oder das Backoffice muss den Bericht prüfen und freigeben. + +### 15.4 Transparenz + +KI-generierte Texte werden als Entwurf gekennzeichnet. + +Die ursprünglichen Notizen bleiben erhalten. + +--- + +## 16. Tagesbericht + +### 16.1 Zweck + +Ein Tagesbericht wird erstellt, wenn ein Auftrag über mehrere Tage läuft oder noch nicht abgeschlossen wurde. + +### 16.2 Inhalte + +- Kunde +- Objekt +- Auftrag +- Datum +- eingesetzte Mitarbeiter +- Arbeitszeiten +- durchgeführte Tätigkeiten +- verwendetes Material +- Fotos +- Abweichungen +- Probleme +- offene Punkte +- geplante nächste Schritte +- Status +- Unterschrift optional + +### 16.3 Ablauf + +1. Monteur beendet den Arbeitstag +2. System prüft Pflichtangaben +3. Berichtsentwurf wird erzeugt +4. Monteur prüft und ergänzt +5. Bericht wird gespeichert +6. Backoffice wird optional informiert +7. Auftrag bleibt geöffnet + +--- + +## 17. Abschlussbericht und Arbeitsnachweis + +### 17.1 Zweck + +Der Abschlussbericht dient als: + +- Leistungsnachweis +- Montagebericht +- Arbeitsnachweis +- Grundlage für die Rechnungsstellung +- interne Dokumentation +- Kundendokumentation + +### 17.2 Inhalte + +- Logo und Unternehmensdaten des Mandanten +- Kunde +- Objekt +- Ansprechpartner +- Auftragsnummer +- Einsatzdatum +- eingesetzte Mitarbeiter +- Arbeitszeiten +- Auftragsbeschreibung +- ausgeführte Leistungen +- Abweichungen +- Zusatzleistungen +- verwendetes Material +- nicht verwendetes Material +- offene Restarbeiten +- Hinweise +- Fotos +- Kundenunterschrift +- Name des Unterzeichners +- Datum und Uhrzeit +- Name des Monteurs +- Berichtsversion + +### 17.3 PDF-Erstellung + +Nach Freigabe wird ein nicht veränderbares PDF erzeugt. + +Das PDF wird: + +- am Auftrag gespeichert +- in der Objekt-Historie abgelegt +- dem Backoffice zur Verfügung gestellt +- optional per E-Mail versendet + +### 17.4 Versionierung + +Änderungen nach Freigabe erzeugen eine neue Berichtsversion. + +Bereits freigegebene Versionen dürfen nicht überschrieben werden. + +--- + +## 18. Digitale Kundenunterschrift + +### 18.1 Funktionen + +Der Kunde kann auf dem Tablet oder Smartphone unterschreiben. + +Zusätzlich werden erfasst: + +- Name des Unterzeichners +- Funktion optional +- Datum +- Uhrzeit +- Bestätigungstext +- Bezug zum Bericht +- Benutzer, der die Unterschrift aufgenommen hat + +### 18.2 Ablehnung oder Abwesenheit + +Folgende Optionen müssen vorhanden sein: + +- Kunde nicht anwesend +- Kunde verweigert Unterschrift +- Unterschrift wird später eingeholt +- Unterschrift nicht erforderlich + +Eine Begründung kann verpflichtend sein. + +--- + +## 19. Notdiensteinsatz + +### 19.1 Ziel + +Ein Monteur muss außerhalb der Geschäftszeiten selbstständig einen neuen Einsatz anlegen können. + +### 19.2 Erfassungsmaske + +Pflichtfelder: + +- Kunde +- Objekt oder Einsatzadresse +- Ansprechpartner +- Telefonnummer +- Grund des Notdiensteinsatzes +- Beginn +- Team oder Monteur + +Optionale Felder: + +- bestehender Kunde auswählen +- neuen vorläufigen Kunden anlegen +- vorhandenes Objekt auswählen +- Fotos +- Sprachnotiz +- Material +- Tätigkeiten +- Kundenunterschrift + +### 19.3 Vorläufige Datensätze + +Falls der Kunde noch nicht existiert, wird ein vorläufiger Kundendatensatz angelegt. + +Status: + +```text +Vorläufig – Prüfung durch Backoffice erforderlich +``` + +Das Backoffice kann am nächsten Arbeitstag: + +- Kunden bestätigen +- bestehenden Kunden zuordnen +- Dublette zusammenführen +- Objekt korrigieren +- Auftrag ergänzen +- Abrechnung freigeben + +### 19.4 Benachrichtigung + +Nach Abschluss eines Notdiensteinsatzes wird das Backoffice automatisch informiert. + +Beispiel: + +```text +Neuer Notdiensteinsatz abgeschlossen + +Monteur: Martin Solarczek +Kunde: Lutz Meier +Einsatzbeginn: 28.07.2026, 23:42 Uhr +Einsatzende: 29.07.2026, 01:18 Uhr +Status: Zur Prüfung und Abrechnung +``` + +Benachrichtigungskanäle im MVP: + +- E-Mail +- interne Benachrichtigung im Dashboard + +Push-Benachrichtigungen können später ergänzt werden. + +--- + +## 20. Benachrichtigungen + +### 20.1 Ereignisse + +Benachrichtigungen sollen unter anderem ausgelöst werden bei: + +- neuer Teamzuweisung +- Änderung eines Auftrags +- Auftrag storniert +- Auftrag gestartet +- Tagesbericht erstellt +- Auftrag technisch abgeschlossen +- Unterschrift fehlt +- Bericht zur Prüfung eingereicht +- Auftrag zur Abrechnung freigegeben +- Notdiensteinsatz erstellt +- Notdiensteinsatz abgeschlossen +- Pflichtangaben fehlen +- Synchronisationsfehler + +### 20.2 Kanäle + +MVP: + +- In-App-Benachrichtigung +- E-Mail + +Später: + +- Web Push +- SMS +- Microsoft Teams +- Slack +- ERP-Webhook + +--- + +## 21. Backoffice-Dashboard + +Das Dashboard zeigt mindestens: + +- offene Aufträge +- heutige Einsätze +- laufende Einsätze +- nicht angenommene Aufträge +- überfällige Aufträge +- Berichte zur Prüfung +- abgeschlossene Aufträge +- Aufträge zur Abrechnung +- neue Notdiensteinsätze +- fehlende Unterschriften +- Synchronisationsfehler + +Filter: + +- Zeitraum +- Kunde +- Objekt +- Team +- Monteur +- Status +- Auftragsart +- Priorität + +--- + +## 22. Mobile Auftragsansicht + +Die mobile Ansicht muss für die Bedienung auf Baustellen optimiert sein. + +Anforderungen: + +- große Schaltflächen +- geringe Texteingabe +- klare Statusanzeige +- gute Lesbarkeit bei Tageslicht +- wenige Navigationsebenen +- Kamera direkt erreichbar +- Materialerfassung mit wenigen Eingaben +- automatische Zwischenspeicherung +- Offline-Hinweis +- Synchronisationsstatus sichtbar + +Empfohlene Hauptnavigation: + +```text +Heute +Aufträge +Notdienst +Synchronisation +Profil +``` + +--- + +## 23. Offline-Fähigkeit + +### 23.1 Ziel + +Ein Auftrag soll auch bei schlechter oder fehlender Internetverbindung bearbeitet werden können. + +### 23.2 Offline verfügbare Daten + +Vor einem Einsatz sollen lokal gespeichert werden: + +- Auftragsdaten +- Kundendaten +- Objektdaten +- Ansprechpartner +- Checklisten +- Materialvorgaben +- relevante Dokumente +- technische Zeichnungen +- letzte freigegebene Einsatzberichte +- notwendige Vorlagen + +### 23.3 Offline erfassbare Daten + +- Arbeitsbeginn und Arbeitsende +- Tätigkeitsnotizen +- Checklisten +- Material +- Fotos +- Sprachnotizen +- Unterschrift +- Tagesbericht +- Abschlussbericht + +### 23.4 Synchronisation + +Lokale Änderungen werden in einer Warteschlange gespeichert. + +Sobald eine Internetverbindung vorhanden ist, erfolgt die Synchronisation. + +Jede Änderung erhält: + +- lokale ID +- Server-ID nach Synchronisation +- Zeitstempel +- Benutzer +- Versionsnummer +- Synchronisationsstatus +- Fehlerstatus + +### 23.5 Konfliktbehandlung + +Bei Konflikten gilt: + +- Daten dürfen nicht stillschweigend überschrieben werden +- Konflikte werden protokolliert +- konfliktfreie Felder werden automatisch synchronisiert +- kritische Konflikte müssen im Backoffice geprüft werden + +--- + +## 24. Dokumentenverwaltung + +### 24.1 Dokumentkategorien + +- Auftragsbestätigung +- technische Zeichnung +- Montageanleitung +- Sicherheitsunterlage +- Arbeitsnachweis +- Tagesbericht +- Abschlussbericht +- Kundenfreigabe +- Foto +- sonstiges Dokument + +### 24.2 Versionierung + +Dokumente müssen versionierbar sein. + +Zu speichern: + +- Version +- Dateiname +- Kategorie +- Ersteller +- Uploaddatum +- Änderungsdatum +- Freigabestatus +- Prüfsumme + +### 24.3 Zugriffsrechte + +Dokumente können markiert werden als: + +- nur Backoffice +- für Teamleiter +- für Montageteam +- für Kundenbericht freigegeben + +--- + +## 25. Suche + +Die Anwendung benötigt eine mandantenbezogene Suche. + +Suchbereiche: + +- Kunden +- Objekte +- Aufträge +- Einsatzberichte +- Auftragsnummern +- Ansprechpartner +- Adressen +- Dokumentnamen +- Notizen + +Filterbare Suchergebnisse: + +- Zeitraum +- Kunde +- Objekt +- Auftragsart +- Status +- Team +- Monteur + +Eine KI-basierte semantische Suche ist nicht Bestandteil des MVP, kann aber später ergänzt werden. + +--- + +## 26. Audit-Logging + +Sicherheits- und fachlich relevante Aktionen müssen protokolliert werden. + +Beispiele: + +- Anmeldung +- fehlgeschlagene Anmeldung +- Benutzer angelegt +- Rolle geändert +- Auftrag importiert +- Extraktionsdaten geändert +- Auftrag zugewiesen +- Status geändert +- Arbeitszeit korrigiert +- Material geändert +- Bericht freigegeben +- PDF erzeugt +- Dokument gelöscht +- Unterschrift erfasst +- Mandanteneinstellung geändert + +Ein Audit-Log enthält: + +- Mandant +- Benutzer +- Aktion +- Objektart +- Objekt-ID +- Zeitstempel +- alte Werte +- neue Werte +- IP-Adresse +- User-Agent +- Ergebnis + +Audit-Logs dürfen durch normale Benutzer nicht verändert oder gelöscht werden. + +--- + +## 27. Datenschutz und Informationssicherheit + +### 27.1 Grundprinzipien + +- Datenschutz durch Technikgestaltung +- Mandantentrennung +- minimale Berechtigungen +- verschlüsselte Datenübertragung +- verschlüsselte Speicherung sensibler Daten +- sichere Passworthashes +- revisionsfähige Protokollierung +- definierte Löschfristen +- Datensicherung +- Wiederherstellbarkeit + +### 27.2 Authentifizierung + +MVP: + +- E-Mail-Adresse und Passwort +- sichere Passwortanforderungen +- Passwort-Reset +- Sitzungsverwaltung +- optional verpflichtende Mehrfaktor-Authentifizierung für Administratoren + +Empfehlung: + +- MFA von Beginn an technisch vorbereiten +- später Microsoft Entra ID und weitere Identity Provider über OIDC integrieren + +### 27.3 Autorisierung + +Autorisierung muss serverseitig erfolgen. + +Prüfung mindestens auf: + +- Mandant +- Rolle +- Team +- Auftragszuweisung +- Dokumentenfreigabe +- Aktion + +### 27.4 Dateisicherheit + +- erlaubte Dateitypen einschränken +- Dateigröße begrenzen +- MIME-Type prüfen +- Dateinamen normalisieren +- Malware-Scan +- direkte öffentliche Dateilinks vermeiden +- zeitlich begrenzte Download-URLs verwenden + +### 27.5 Löschkonzept + +Daten dürfen nicht ausschließlich durch hartes Löschen entfernt werden. + +Für fachliche Datensätze wird zunächst Soft Delete verwendet. + +Berichte und abrechnungsrelevante Nachweise erhalten mandantenbezogene Aufbewahrungsfristen. + +--- + +## 28. Datenmodell – Hauptentitäten + +### 28.1 Tenant + +```text +Tenant +- id +- name +- slug +- status +- settings +- created_at +- updated_at +``` + +### 28.2 User + +```text +User +- id +- tenant_id +- email +- password_hash +- first_name +- last_name +- phone +- status +- last_login_at +- created_at +- updated_at +``` + +### 28.3 Role + +```text +Role +- id +- tenant_id +- name +- permissions +``` + +### 28.4 Team + +```text +Team +- id +- tenant_id +- name +- leader_user_id +- status +``` + +### 28.5 TeamMember + +```text +TeamMember +- team_id +- user_id +- valid_from +- valid_to +``` + +### 28.6 Customer + +```text +Customer +- id +- tenant_id +- customer_number +- company_name +- first_name +- last_name +- address +- contact_data +- status +- is_provisional +``` + +### 28.7 Site + +```text +Site +- id +- tenant_id +- customer_id +- name +- address +- contact_person_id +- access_notes +- safety_notes +- technical_notes +``` + +### 28.8 WorkOrder + +```text +WorkOrder +- id +- tenant_id +- customer_id +- site_id +- external_order_number +- order_type +- priority +- status +- title +- description +- planned_start +- planned_end +- assigned_team_id +- signature_required +- source_document_id +``` + +### 28.9 WorkSession + +```text +WorkSession +- id +- tenant_id +- work_order_id +- user_id +- team_id +- type +- started_at +- ended_at +- status +``` + +### 28.10 MaterialPlan + +```text +MaterialPlan +- id +- tenant_id +- work_order_id +- name +- article_number +- planned_quantity +- unit +``` + +### 28.11 MaterialUsage + +```text +MaterialUsage +- id +- tenant_id +- work_order_id +- material_plan_id +- name +- article_number +- actual_quantity +- unit +- usage_status +- deviation_reason +``` + +### 28.12 Report + +```text +Report +- id +- tenant_id +- work_order_id +- type +- version +- status +- content +- pdf_document_id +- approved_by +- approved_at +``` + +### 28.13 Document + +```text +Document +- id +- tenant_id +- customer_id +- site_id +- work_order_id +- category +- file_name +- storage_key +- mime_type +- file_size +- checksum +- version +- visibility +``` + +### 28.14 Notification + +```text +Notification +- id +- tenant_id +- user_id +- type +- title +- message +- read_at +- sent_at +``` + +### 28.15 AuditLog + +```text +AuditLog +- id +- tenant_id +- user_id +- action +- entity_type +- entity_id +- old_values +- new_values +- ip_address +- user_agent +- created_at +``` + +--- + +## 29. API-Konzept + +Die Anwendung soll über eine versionierte API verfügen. + +Beispiel: + +```text +/api/v1/ +``` + +### 29.1 Beispiel-Endpunkte + +```text +POST /api/v1/auth/login +POST /api/v1/auth/logout +POST /api/v1/auth/refresh + +GET /api/v1/customers +POST /api/v1/customers +GET /api/v1/customers/{id} +PATCH /api/v1/customers/{id} + +GET /api/v1/sites +POST /api/v1/sites +GET /api/v1/sites/{id}/history + +GET /api/v1/work-orders +POST /api/v1/work-orders +GET /api/v1/work-orders/{id} +PATCH /api/v1/work-orders/{id} +POST /api/v1/work-orders/{id}/assign +POST /api/v1/work-orders/{id}/start +POST /api/v1/work-orders/{id}/pause +POST /api/v1/work-orders/{id}/complete + +POST /api/v1/work-orders/import +GET /api/v1/imports/{id} +POST /api/v1/imports/{id}/confirm + +POST /api/v1/work-orders/{id}/materials +POST /api/v1/work-orders/{id}/photos +POST /api/v1/work-orders/{id}/voice-notes + +POST /api/v1/work-orders/{id}/daily-report +POST /api/v1/work-orders/{id}/completion-report +POST /api/v1/reports/{id}/approve +GET /api/v1/reports/{id}/pdf + +POST /api/v1/emergency-orders +POST /api/v1/sync +``` + +### 29.2 API-Anforderungen + +- REST oder vergleichbares klar definiertes API-Modell +- OpenAPI-Dokumentation +- konsistente Fehlercodes +- Pagination +- Filter +- Sortierung +- Idempotency Keys für kritische mobile Aktionen +- Rate Limiting +- Mandantenprüfung +- Rollenprüfung +- Audit-Logging + +--- + +## 30. Technologievorschlag + +Der konkrete Stack kann angepasst werden. + +### 30.1 Frontend + +Empfehlung: + +- Next.js oder React +- TypeScript +- responsive UI-Komponenten +- PWA Service Worker +- IndexedDB für Offline-Daten +- React Query oder vergleichbare Datenabstraktion +- Formularvalidierung mit Zod +- PDF- und Bildvorschau + +### 30.2 Backend + +Mögliche Varianten: + +**Variante A** + +- TypeScript +- NestJS +- Prisma ORM +- PostgreSQL + +**Variante B** + +- Python +- FastAPI +- SQLAlchemy +- PostgreSQL + +Für eine einheitliche TypeScript-Codebasis wird Variante A empfohlen. + +### 30.3 Dateispeicher + +- S3-kompatibler Object Storage +- MinIO für lokale oder selbst gehostete Umgebungen +- alternativ Cloudflare R2, AWS S3 oder Azure Blob Storage + +### 30.4 Hintergrundverarbeitung + +Für folgende Aufgaben ist eine Job Queue erforderlich: + +- OCR +- KI-Extraktion +- Transkription +- PDF-Erstellung +- Bildoptimierung +- E-Mail-Versand +- Benachrichtigungen +- Synchronisationsnachverarbeitung + +Mögliche Technologien: + +- Redis +- BullMQ +- Celery bei Python +- RabbitMQ optional + +### 30.5 Bereitstellung + +Empfehlung: + +- Docker +- Docker Compose für Entwicklung +- Coolify für Hosting +- PostgreSQL +- Redis +- Object Storage +- Reverse Proxy +- TLS +- getrennte Entwicklungs-, Test- und Produktionsumgebung + +--- + +## 31. KI- und OCR-Abstraktion + +KI- und OCR-Funktionen dürfen nicht fest mit einem einzigen Anbieter verbunden werden. + +Es wird eine Provider-Abstraktion empfohlen. + +Beispiel: + +```typescript +interface DocumentExtractionProvider { + extractText(file: Buffer): Promise<ExtractedText>; + extractStructuredData(text: string): Promise<WorkOrderExtraction>; +} +``` + +Mögliche Provider: + +- Azure AI Document Intelligence +- Google Document AI +- AWS Textract +- Tesseract OCR +- OpenAI +- Anthropic +- lokales Sprachmodell + +Konfiguration je Mandant oder Plattform: + +- Provider +- Modell +- Region +- Datenschutzoptionen +- Aufbewahrung +- maximale Dateigröße +- Kostenlimit + +--- + +## 32. PDF-Berichtsgenerierung + +Berichte sollen über HTML-Templates erzeugt und als PDF gerendert werden. + +Mögliche Technologien: + +- Playwright +- Puppeteer +- serverseitige HTML-zu-PDF-Engine + +Vorteile: + +- anpassbares Layout +- Mandantenlogo +- individuelle Berichtsvorlagen +- saubere Seitenumbrüche +- Fotoübersichten +- Unterschriftenintegration + +Jeder erzeugte Bericht erhält: + +- eindeutige Bericht-ID +- Versionsnummer +- Erstellungsdatum +- Prüfsumme +- Freigabestatus + +--- + +## 33. E-Mail-Versand + +### 33.1 E-Mail-Ereignisse + +- Teamzuweisung +- Bericht zur Prüfung +- Auftrag zur Abrechnung +- Notdiensteinsatz +- Fehler bei der Dokumentverarbeitung + +### 33.2 Konfiguration + +Je Mandant konfigurierbar: + +- Absendername +- Absenderadresse +- Empfänger für Notdienste +- Empfänger für Abrechnung +- Antwortadresse +- E-Mail-Vorlagen + +### 33.3 Technische Umsetzung + +Mögliche Anbindung: + +- SMTP +- Microsoft Graph +- Amazon SES +- Mailgun +- Postmark + +E-Mails werden über eine Warteschlange versendet. + +Versandstatus und Fehler werden protokolliert. + +--- + +## 34. Nichtfunktionale Anforderungen + +### 34.1 Performance + +- Standardseiten sollen innerhalb von zwei Sekunden reagieren +- Auftragslisten müssen paginiert werden +- Bilder werden asynchron geladen +- große Dokumente werden im Hintergrund verarbeitet +- Uploadfortschritt muss sichtbar sein + +### 34.2 Verfügbarkeit + +Für den MVP wird eine Zielverfügbarkeit von 99,5 Prozent empfohlen. + +### 34.3 Skalierbarkeit + +Die Architektur muss horizontal erweiterbar sein. + +Insbesondere: + +- stateless Backend +- externer Dateispeicher +- zentrale Datenbank +- Redis oder Queue-System +- getrennte Worker + +### 34.4 Browserunterstützung + +- aktuelle Version von Chrome +- aktuelle Version von Edge +- aktuelle Version von Safari +- aktuelle Version von Firefox +- mobile Browser unter iOS und Android + +### 34.5 Barrierearme Bedienung + +- ausreichende Kontraste +- verständliche Beschriftungen +- Tastaturbedienung im Backoffice +- große Touch-Ziele +- Fehlermeldungen in Klartext + +--- + +## 35. MVP-Abgrenzung + +Nicht Bestandteil des initialen MVP: + +- native iOS-App +- native Android-App +- vollständige Lagerverwaltung +- automatische Bestandsbuchung +- vollständige Anlagenverwaltung +- Seriennummern- und Gerätehistorie +- Rechnungsstellung +- Finanzbuchhaltung +- direkte DATEV-Schnittstelle +- direkte ERP-Schnittstellen +- automatische Tourenoptimierung +- GPS-Dauertracking +- Fahrzeugverwaltung +- Kundenportal +- Lieferantenportal +- automatische Angebotserstellung +- komplexe Ressourcenplanung +- Lohnabrechnung +- vollautomatische KI-Freigaben +- semantische Suche über alle Dokumente + +--- + +## 36. Priorisierung + +### 36.1 Muss-Funktionen für den MVP + +- Multitenancy +- Benutzer und Rollen +- Kunden +- Objekte +- Teams +- PDF-Import +- OCR und Datenextraktion +- manuelle Prüfmaske +- Aufträge +- Teamzuweisung +- mobile PWA +- eingeschränkte Offline-Nutzung +- Arbeitszeiten +- Tätigkeitsdokumentation +- Materialdokumentation +- Fotos +- Checklisten +- Tagesbericht +- Abschlussbericht +- PDF-Erstellung +- Kundenunterschrift +- Notdiensteinsatz +- Backoffice-Benachrichtigung +- Objekt-Historie +- technische Dokumente +- Audit-Logging + +### 36.2 Soll-Funktionen + +- Sprachnotizen +- Transkription +- KI-Berichtsentwurf +- konfigurierbare Vorlagen +- E-Mail-Versand von Berichten +- Berichtsversionierung +- MFA +- Kartenlink zur Einsatzadresse + +### 36.3 Kann-Funktionen + +- Push-Benachrichtigungen +- Kalenderansicht +- Standorterfassung beim Einsatzstart +- Barcode- oder QR-Code-Erfassung +- kundenspezifische Statusmodelle +- digitale Einsatzfreigabe durch Teamleiter + +--- + +## 37. User Stories + +### US-001 – Mandant anlegen + +**Als Plattformadministrator** +möchte ich einen neuen Handwerksbetrieb als Mandanten anlegen, +damit dieser die Anwendung mit vollständig getrennten Daten nutzen kann. + +**Akzeptanzkriterien:** + +- Mandant erhält eine eindeutige ID +- Mandantenadministrator kann angelegt werden +- Daten anderer Mandanten sind nicht sichtbar +- Mandant kann deaktiviert werden + +--- + +### US-002 – Auftragsbestätigung importieren + +**Als Backoffice-Mitarbeiter** +möchte ich eine Auftragsbestätigung als PDF hochladen, +damit Kunden-, Objekt- und Auftragsdaten automatisch übernommen werden. + +**Akzeptanzkriterien:** + +- PDF kann hochgeladen werden +- Text wird erkannt +- strukturierte Felder werden extrahiert +- unsichere Felder werden markiert +- Daten können korrigiert werden +- Auftrag wird erst nach Bestätigung angelegt +- Originaldokument bleibt gespeichert + +--- + +### US-003 – Bestehenden Kunden erkennen + +**Als Backoffice-Mitarbeiter** +möchte ich beim Import erkennen, ob der Kunde bereits existiert, +damit keine unnötigen Dubletten entstehen. + +**Akzeptanzkriterien:** + +- System prüft Kundennummer, Name und Adresse +- mögliche Treffer werden angezeigt +- Benutzer entscheidet über Zuordnung +- keine automatische Zusammenführung ohne Bestätigung + +--- + +### US-004 – Auftrag einem Team zuweisen + +**Als Backoffice-Mitarbeiter** +möchte ich einen Auftrag einem Montageteam zuweisen, +damit das Team den Auftrag auf dem Tablet bearbeiten kann. + +**Akzeptanzkriterien:** + +- Team kann ausgewählt werden +- Auftrag erscheint in der mobilen Ansicht +- Team wird benachrichtigt +- Zuweisung wird protokolliert + +--- + +### US-005 – Technische Unterlagen ansehen + +**Als Monteur** +möchte ich technische Zeichnungen und frühere Einsatzberichte am Objekt ansehen, +damit ich den aktuellen Einsatz korrekt durchführen kann. + +**Akzeptanzkriterien:** + +- relevante Dokumente sind am Auftrag sichtbar +- freigegebene frühere Berichte sind sichtbar +- Dokumente können vorab offline gespeichert werden +- Backoffice-interne Dokumente bleiben verborgen + +--- + +### US-006 – Einsatz dokumentieren + +**Als Monteur** +möchte ich Arbeiten, Zeiten, Fotos, Material und Notizen erfassen, +damit ein vollständiger Arbeitsnachweis entsteht. + +**Akzeptanzkriterien:** + +- Einsatz kann gestartet und beendet werden +- Fotos können aufgenommen werden +- Materialmengen können bestätigt oder geändert werden +- Zusatzmaterial kann erfasst werden +- Notizen bleiben bei Verbindungsabbruch erhalten + +--- + +### US-007 – Tagesbericht erstellen + +**Als Monteur** +möchte ich am Ende eines Arbeitstages einen Tagesbericht erstellen, +damit der Fortschritt eines mehrtägigen Auftrags dokumentiert ist. + +**Akzeptanzkriterien:** + +- Bericht enthält Arbeitszeiten und Tätigkeiten +- offene Punkte können dokumentiert werden +- Fotos können eingebunden werden +- Auftrag bleibt geöffnet +- Bericht erscheint in der Objekt-Historie + +--- + +### US-008 – Abschlussbericht erstellen + +**Als Monteur** +möchte ich nach Abschluss einen Bericht erzeugen, +damit der Kunde und das Backoffice einen Leistungsnachweis erhalten. + +**Akzeptanzkriterien:** + +- Pflichtangaben werden geprüft +- Pflichtfotos werden geprüft +- Materialabweichungen sind enthalten +- Kundenunterschrift kann erfasst werden +- PDF wird erzeugt +- Auftrag erhält den Status „Zur Prüfung“ + +--- + +### US-009 – Auftrag zur Abrechnung freigeben + +**Als Backoffice-Mitarbeiter** +möchte ich einen abgeschlossenen Auftrag prüfen und zur Abrechnung freigeben, +damit die Rechnung erstellt werden kann. + +**Akzeptanzkriterien:** + +- Bericht ist einsehbar +- Arbeitszeiten sind einsehbar +- Material ist einsehbar +- Bericht kann freigegeben oder zurückgewiesen werden +- Freigabe wird protokolliert +- zuständige Stelle wird benachrichtigt + +--- + +### US-010 – Notdiensteinsatz anlegen + +**Als Monteur** +möchte ich außerhalb der Geschäftszeiten selbst einen Notdiensteinsatz anlegen, +damit der Einsatz vollständig dokumentiert und später abgerechnet werden kann. + +**Akzeptanzkriterien:** + +- bestehender Kunde kann ausgewählt werden +- vorläufiger Kunde kann angelegt werden +- Objekt oder Einsatzadresse kann erfasst werden +- Zeiten, Tätigkeiten, Material und Fotos können dokumentiert werden +- Abschlussbericht kann erstellt werden +- Backoffice wird automatisch informiert +- Einsatz ist am nächsten Arbeitstag zur Prüfung sichtbar + +--- + +### US-011 – Objekt-Historie aufrufen + +**Als Monteur oder Backoffice-Mitarbeiter** +möchte ich die bisherigen Einsätze eines Objekts einsehen, +damit frühere Arbeiten und technische Hinweise berücksichtigt werden. + +**Akzeptanzkriterien:** + +- chronologische Liste aller freigegebenen Einsätze +- Berichte und Fotos sind abrufbar +- verwendetes Material ist sichtbar +- offene Folgearbeiten werden hervorgehoben + +--- + +### US-012 – Offline arbeiten + +**Als Monteur** +möchte ich einen Auftrag ohne stabile Internetverbindung bearbeiten, +damit die Dokumentation auf Baustellen nicht unterbrochen wird. + +**Akzeptanzkriterien:** + +- Auftragsdaten sind offline verfügbar +- Eingaben werden lokal gespeichert +- Fotos werden in die Uploadwarteschlange aufgenommen +- Synchronisationsstatus ist sichtbar +- Daten werden nach Wiederherstellung der Verbindung übertragen +- Konflikte werden nicht stillschweigend überschrieben + +--- + +## 38. Beispielprozess – regulärer Auftrag + +```text +Backoffice lädt Auftragsbestätigung hoch + ↓ +OCR und KI extrahieren Daten + ↓ +Backoffice prüft Kunden-, Objekt- und Auftragsdaten + ↓ +Bestehender Kunde und bestehendes Objekt werden zugeordnet + ↓ +Auftrag wird einem Montageteam zugewiesen + ↓ +Team lädt Auftrag und Dokumente auf das Tablet + ↓ +Monteur startet Einsatz + ↓ +Arbeiten, Zeiten, Material, Fotos und Notizen werden erfasst + ↓ +Monteur erstellt Abschlussbericht + ↓ +Kunde unterschreibt + ↓ +PDF-Arbeitsnachweis wird erzeugt + ↓ +Backoffice prüft Bericht + ↓ +Auftrag wird zur Abrechnung freigegeben + ↓ +Einsatz erscheint in der Objekt-Historie +``` + +--- + +## 39. Beispielprozess – Notdiensteinsatz + +```text +Monteur erhält außerhalb der Geschäftszeit einen Anruf + ↓ +Monteur öffnet „Notdienst“ + ↓ +Bestehender Kunde wird ausgewählt oder vorläufig angelegt + ↓ +Einsatzadresse und Störungsgrund werden erfasst + ↓ +Einsatz wird gestartet + ↓ +Arbeiten, Material, Fotos und Zeiten werden dokumentiert + ↓ +Kunde unterschreibt oder Abwesenheit wird dokumentiert + ↓ +Abschlussbericht wird erzeugt + ↓ +Backoffice erhält E-Mail und In-App-Benachrichtigung + ↓ +Backoffice prüft am nächsten Arbeitstag die Stammdaten + ↓ +Auftrag wird zur Abrechnung freigegeben +``` + +--- + +## 40. Akzeptanzkriterien für den Gesamt-MVP + +Der MVP gilt als fachlich abnahmefähig, wenn: + +1. mehrere Mandanten mit sicher getrennter Datenhaltung betrieben werden können +2. Benutzer, Rollen und Montageteams verwaltet werden können +3. Auftragsbestätigungen als PDF importiert werden können +4. Kunden-, Objekt- und Auftragsdaten automatisiert extrahiert werden +5. das Backoffice die erkannten Daten prüfen und korrigieren kann +6. Aufträge Teams zugewiesen werden können +7. Monteure Aufträge auf Tablets und Smartphones bearbeiten können +8. wesentliche Daten offline erfasst werden können +9. Arbeitszeiten, Tätigkeiten, Material und Fotos dokumentiert werden können +10. Tagesberichte erzeugt werden können +11. Abschlussberichte inklusive Kundenunterschrift erzeugt werden können +12. ein PDF-Arbeitsnachweis erstellt wird +13. das Backoffice abgeschlossene Aufträge zur Abrechnung freigeben kann +14. Monteure selbstständig Notdiensteinsätze anlegen können +15. das Backoffice über Notdiensteinsätze informiert wird +16. frühere Einsätze und technische Dokumente pro Objekt abrufbar sind +17. relevante Änderungen revisionsfähig protokolliert werden + +--- + +## 41. Empfohlene Entwicklungsphasen + +### Phase 0 – Technische Basis + +- Repository +- CI/CD +- Docker +- Datenbank +- Authentifizierung +- Mandantenkontext +- Rollen und Berechtigungen +- Logging +- Object Storage +- Grundlayout + +### Phase 1 – Stammdaten und Aufträge + +- Kunden +- Ansprechpartner +- Objekte +- Teams +- Benutzer +- Aufträge +- Statusmodell +- Dokumentenupload +- Teamzuweisung + +### Phase 2 – PDF-Import + +- Upload +- OCR +- Extraktion +- Prüfmaske +- Dublettenprüfung +- Auftragsentwurf +- Originaldokument + +### Phase 3 – Mobile Einsatzbearbeitung + +- PWA +- mobile Auftragsliste +- Einsatzstart +- Arbeitszeiten +- Checklisten +- Material +- Fotos +- Notizen +- Offline-Speicherung + +### Phase 4 – Berichte + +- Tagesbericht +- Abschlussbericht +- Unterschrift +- PDF-Erstellung +- Berichtsversionen +- Backoffice-Freigabe + +### Phase 5 – Notdienst + +- Notdiensteinsatz +- vorläufiger Kunde +- vorläufiges Objekt +- Benachrichtigungen +- Nachbearbeitung im Backoffice + +### Phase 6 – Stabilisierung + +- Audit-Logging +- Sicherheitsprüfungen +- Lasttests +- Offline-Konflikte +- Backup und Restore +- Monitoring +- Fehlerbehandlung +- Pilotbetrieb + +--- + +## 42. Definition of Done + +Eine Funktion gilt als fertig, wenn: + +- fachliche Anforderungen umgesetzt sind +- Mandantentrennung geprüft wurde +- Rollen- und Rechteprüfung vorhanden ist +- Eingaben validiert werden +- Fehlerfälle behandelt werden +- relevante Aktionen protokolliert werden +- automatisierte Tests vorhanden sind +- API dokumentiert ist +- responsive Darstellung geprüft wurde +- Offline-Verhalten geprüft wurde, sofern relevant +- Datenschutzanforderungen berücksichtigt sind +- technische Dokumentation aktualisiert wurde +- Funktion in einer Testumgebung abgenommen wurde + +--- + +## 43. Teststrategie + +### 43.1 Unit-Tests + +- Datenvalidierung +- Statusübergänge +- Berechtigungen +- Mandantenfilter +- Materialberechnungen +- Berichtsgenerierung +- Extraktionsmapping + +### 43.2 Integrationstests + +- PDF-Import +- OCR-Verarbeitung +- Dateiupload +- E-Mail-Versand +- PDF-Erstellung +- Datenbank +- Object Storage +- Queue-Verarbeitung + +### 43.3 End-to-End-Tests + +- regulärer Auftrag vom Import bis zur Freigabe +- mehrtägiger Auftrag mit Tagesbericht +- Notdiensteinsatz +- Offline-Erfassung und Synchronisation +- fehlende Pflichtfotos +- fehlende Unterschrift +- Dublettenprüfung +- Mandantentrennung + +### 43.4 Sicherheitstests + +- Zugriff auf fremde Mandantendaten +- manipulierte IDs +- unzulässige Rollenaktionen +- schädliche Uploads +- Session-Handling +- Rate Limiting +- Passwort-Reset +- Audit-Log-Manipulation + +--- + +## 44. Offene fachliche Entscheidungen vor Produktivbetrieb + +Folgende Punkte müssen spätestens während der Umsetzung konkretisiert werden: + +- genaue Berichtsvorlage des Pilotkunden +- Pflichtfelder je Auftragsart +- erforderliche Fotoarten +- Regelung der Arbeitszeitkorrektur +- Aufbewahrungsfristen +- Empfänger der Abrechnungsbenachrichtigung +- bevorzugter OCR- und KI-Anbieter +- gewünschter E-Mail-Dienst +- Hostingstandort +- gewünschte MFA-Regelung +- Umgang mit Standortdaten +- maximale Offline-Dauer +- maximale Dateigrößen +- konkrete Buchhaltungssoftware des Pilotkunden +- später gewünschte Schnittstellen +- Unternehmensbranding der PWA +- Berichtssprache +- Lösch- und Archivierungskonzept + +--- + +## 45. Perspektive für Version 2 + +Für Version 2 werden folgende Erweiterungen empfohlen: + +- direkte Schnittstelle zum Buchhaltungs- oder ERP-System +- Artikel- und Materialstamm +- Lagerbestände +- automatische Übergabe abrechnungsrelevanter Positionen +- Kalender und Einsatzplanung +- Routenplanung +- Kundenportal +- Wartungsplanung +- Anlagen- und Geräteverwaltung +- Seriennummern +- QR-Codes an Objekten oder Anlagen +- automatische Erinnerungen +- Web-Push-Benachrichtigungen +- Microsoft-365-Integration +- DATEV-Export +- KI-Suche in Einsatzhistorien +- KI-Assistent für Monteure +- automatische Zusammenfassung früherer Einsätze +- Auswertung von Nachkalkulationen +- Kennzahlen je Team, Auftrag und Kunde +- konfigurierbare Workflows je Mandant + +--- + +## 46. Zusammenfassung + +Der MVP soll eine mandantenfähige PWA für Handwerks- und Montagebetriebe bereitstellen. + +Der Kernnutzen besteht darin, Auftragsdaten aus bestehenden PDF-Dokumenten zu übernehmen, Montageteams digital mit allen notwendigen Informationen zu versorgen und aus der tatsächlichen Arbeit vor Ort einen vollständigen, abrechnungsfähigen Nachweis zu erzeugen. + +Besonders wichtig sind: + +- geringe manuelle Datenerfassung +- einfache Bedienung auf der Baustelle +- Offline-Fähigkeit +- vollständige Foto- und Materialdokumentation +- Tages- und Abschlussberichte +- Notdiensteinsätze ohne Backoffice +- dauerhafte Objekt-Historie +- technische Dokumente am Objekt +- sichere Mandantentrennung +- modular erweiterbare Architektur + +Die Lösung bildet damit die Grundlage für eine später umfassendere SaaS-Plattform für Handwerks- und Montagebetriebe. diff --git a/docs/craftvia/assets/craftvia-brand-identity-v1.png b/docs/craftvia/assets/craftvia-brand-identity-v1.png new file mode 100644 index 0000000000000000000000000000000000000000..66eea9e2b809c4f987458060aab080d926b7a1f9 GIT binary patch literal 1303800 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≶%5-+Wg=QalUv{cD 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Ð?P$ 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�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 Dd_mB<p*4zw8#iY16WH4{FHQsu|G5{2U<0 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 N%>?x>ocLwJmWID?$P-BYHIs3^w8AYrOjb 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∓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∓{2e(IKz+~TPjM+gtY!XLlLNG^VO^IwM- z{Hfa9Hsn<Mm($NL`*LZ{?&lKz9F=E_pZDCc756^5+&Odq<zfFUoz^XR`03yxKTNM6 zoEXzQx~b@(+~wVBhGoQl@XOi1hY#~>{4j<<BjyOHxiMPr)$Z~)p`}|-z!R}(E8KAJ zkSzKz=Ft7)k(`d5Wj`Jt_1YJoEN?5$`h8aCkFD$Vf%+|vO{t7<co^$P_WUt^c6{q& z<I?6-jv2H4)4^L-im7<j{cSm~VU&Af@ST0{f0Nx*{MOlj9co@Z`zhCKCDk{4+BoIi z(WZ15ey7NTV&`?&#M1<5eLX)uh92(}J1C02yetn46R<|^EDno=DBseY!UD!sEHPrB z>}CC=&<&%GlFJ?Rn9Entd2Yas+`i@9av|k+igi$>9aP)eavBQj=jZYCXQ1q2XL)DI zGR*0FA|Wu9=F;j+Ctv`eu`SY|Wt?`L0cEZV-+Q4oLl$FTi8F>yfCA4!&=DYFuFf7B zZ76*dz{qMG78R^?=3rAzY88;^8nmmv)K*sLB#4MORZHOT)uS_j!CHf3%vwqt0M*qh z;0(rcy#cR8q|Hp9fv8xAr7M0=X6uWQ5|IsHXDI7RqWa0Aip&q<kU+AHv{_-Ge}`7G z1-I3B`~M>ZGHj<dflr7g3MG{{eif#u1u)wLO*hQPI2zMd8>b}_!uEp<O`z5SPGv&_ z2o+j>8g8?2x-k$^X~p(#Y(i<0U7j2jjyL0#5FD?dI9t6CzV0zNF4+dUy*l{tcWAOy zh6+8USPa+<`lVb<H3V0pT&%!YB_P?R1_z+-Lc`_^nxYu^P~jp_rtnQu4BF^X96^QR zK8S%38v_}OHz~pBcEK=gi)1!{^VsdlMGq!9MKHcON=%k$c^~Q1p!xYlM8k|Sc!_zy zZQiMacqV902${hF<fBE0z*WV#RY*Cbi~frz(iMkUtHp(diwSbegV8(aGZ!HZsU5To z8a`pt@TmeZ{x+q7{}Q2)Qe-pt9$7Fk%an`3QI8cFu_tSfl}w-0q^<4U|MWaYx8`n6 zFRcdJ0X4kd^dvqbwj;CW`6(%Q+hUyRQ77qEyDjdp^wji|FI9fQn6ft~I-Ow=#WIX5 zc1B%gMxMZP41^**@kZ;!5d$G*k|eG)YQ;(iZdyal6eYfYTwDqw^t^y6I>{EoQF323 z#2E*S48<7gAd<4++L)0|!<YXwIp>#IU6teO=9TYx__ISt>8^h3x_qUq>)FKn-N$!c zt;(2I`o^9|hA(+zU-s%Xo$p<`cfCHl?YSS$Q0y6gxbVa64;I{Acj?~h0smfqdhp>h zNBb>2wYVC>AkP>ZwVHvwdblz)qr%)Ht*<B@n|^5izVF>1<8uByH~#6jIvYx>ZjN3& z1I3Bk{`f;L7Al|ojeWyFHN_AQb;9i9o(D;0S4R2R_@?xy!cW6sQLKut%>k@ku1Xso zcbW^FOR>jEMN0(e3B<RQ`;{u>ux`?J!Y?kaZ}jW)(2RfXI`^+zIsZC07)Clmnkgrg z22*(u%$%1GJU(~MoX_F{?1P(kEUT|N{#?%Y(eLeO*nKdwEiSPu{D+^e%}kv3taElG zgNj|d+!@<;=?!*i2bi?z@{!g+rD73iQzJEY2Y?cB#r6GDkquxbH^z=dF2Xl9G?g=J zhasd;*dQ_jK4S>f8;kgpiXCHIY8pYfap{~aY!vpQ)JQJ~@Pj)Mdq)utFDSFnTDkVY z@bfY(>?$1Oy(?dlZ}Q5GbR~l$b2Gq76;(~m2hfzDWY9!Ne|^{ih%$sD105^GS262i z4qY}9npgk4Xj7_Rh^l#37;{OA0jvvVH_zfYQt*#Jf`mmli<d4+(ZZ*S+PIJUCxh%% z&xSszm*b=G?YuA^%^}=8Y~?t@+({gULY$Ra3n>z%FTIwqM+E4JWOvd!?dBZMyM4}J z^cO^^ZA`3!fo3+WMhI6#At>H{Llx;Ov`Q;FO)iX-PG~13wf8Lkql!>N;M7$=674Zf zoJU>SYH}q}FGX|ROQ$kb&}v3hYYQwOmeeXZg#ksIuoRm`*ZrV>qsR+`1*JgmHQeu^ z)yHF?2Ev!%7|qv;8@+?VIJ;j+p8SlN10{OKu7vl6J!8Qtkna>-){ba#{zKFeHwuLV zuo&Y$2ZvE4QR<BOD*&13wV-p*(qE|OBtb2)g8p0XUg#1$lIb*mUJ9T^tQ(MT1X9#g z$(u$;Z$L_>=G1^t3f$v4sKe?KMrWuV+L;(qb4MmNcN6Gb<pSX#6sCT3a^=>6mj@0# zvM6S<vB~u0=^?u|edBO$DoO9JuTZ7>B<JSuDmXpRw%#>6x?1PwXPr_s#5dO#bY#)% z=S#FUbDOnf+_Zh`++pg0%CIJ%#|-%e1q<W#_3J8QBT)A?j?$?NqJ(B0kj>g8-j~Tf z#!zJ&e`@Qo0??|de}R=zJxy#QdWWqB)wnNbtBu{#<7yhC<7>2vpBsBG><9@^;6aqa z(&SXyb>y3OO8;@bWaRO&sk<J(u_XTPv>i`(Jsfqbd`-^YbEL?1eX{0G^@17wwwKiH z*}o^Dsv~LE?=z~}uWg?G8YF<o%}?!Vk6+OFp3~qk!yZJGJMKAg>DpR*EE(E;SVqLw zO*?-t3S4%lc=_kMGAf?bC@Xyay=|2){JW#>q_ZEtWBEXrQd2U&<n4)JVGITbY>SJ# zM&gVTdTL4YI~l{Tjd3W)R)<}yedD~|pi4nywlRJnGDp#2tZ-N&SIAg1nBc9y6(zm5 zy5rrW-;UV(QNfnXGh+vUx(+|hsNQ78y42J-W&OO8FMJ2Y&o7x5ns#tz;DW9Rv$DE& z`0aYK&&}hDZruA}K}SfxwwsNyM~v|5!kgl!7}SHh4Re@P+VVmfI4kQaGgNx>n6M_) zP&ExN4Ggm|Xy3hO&a>o^!YXd3#^z}9VL7$hOLKa{rKjFcqA=*7-@moHF!M-lPIupF z07WteqaBB51ner{7+Zsc%W}H+czdX{XA$fP@QJLD5qngl6Wp`&ag%tEevAoVOE!m= zVBae2bqE4f)WBS%h3*cKp2nk8g6K@CVJA*con{dGg0&vpS=j&BmeZq9_{lD^A|Yw- zOfd?RafkRMctd&R;ELCXf`ARMYA^>eB~$w&0;3y>z$WMpy_tV9ASnO_=XLeqkCpUk z(&ZKV>Ls`WO=M>O(O^hxd<fn`O`=O>(zU3hj;hPCUV2;XGL_^8$QRR!0;V{9Dqvt~ zF<AkSMeCLhBa7h*98_%c2rKq!2xb~5$d4E~LJPv;-x{x|DgH)6eUl>(vKjaU?}{SR zYf^%eQ-j(TIw^lKE=0p&ii#206)m%uQzAd_!A?e#LZ;wjGM1wJZF3MPXC_e_1X*O7 z?cu3@ipU+^F{5xM2thUpX-3GAUanxOXf68-dA|W=Gff!tbo@bZ#L;4P80YjkQCZ*v z_j{(d*b=yr4qFTbWKbm;i86HacSc^Hi{CU3Go*WA0|s#l4wQhByj?F7CxvC+MBFvZ zO(Y6luP&*HL>k^TQa%_{IW|TQ5ibgKs)8%YQ7M>ap4cI3ga<D6OU?lAOr#Mv2_vXj zSsiEYdS&Hzv5b40YT_$%zsT4Y+W6a;y$;{>^TccSns{nS$BfqNhi_Cj`YqeOCvHGx zzvZVNpF3`I{>m@74xofq=xs)eWvlV4%l*ohpF4fy={`4yoGW{C*K-#x+?tVm!tRS; zwV{7T^m~sjy|n1&^<_hcHLbeR^u(p*7Z2W0Tr>O|P7D;=mm=_vCsVeG0GaI_-GBgS z$>?nbJ#~Y^l)NLOY!l~vdF}mWHxAxveslT_M`YhOPVaeQM$V|B^zWS4&PE0WB@9@l z9x-)jF{0^9m;bTnEyvZCtMx9Qp@wlA8|H1x=sAytT|Oi?rgGKFFJcUeSd3sOuJcmW zE1z}ldbC$WWlT-j>2Hqh*mLkk)8SuNKmF%{bIb16Pg|3AX5yL!_r7NWR^N5L-=TY@ zhhFMGS!a7bG}Pjoo;J;vTx9w<`H{XuHvgHw?8fk_C;olzi5ZKUBl>o@U+w|EjvHZq zVd3dt)`9Q6JtwVTs(Gcltbf4JrU_ehEQS&GUK2+seU{!@P<6HQ`jH89<}Zkxf1vBk zp1JQ2?zKJx;&?_{WLk3i>mROXBu-J`=ie|aBhT{p?H89_`u|uu^LQxt_l*xpl(Mv_ zlo?B*(zH@pMxrd0QYRf^l*$pBqzr}`LQ+H&$(9N^jxE{3j3Sb)vKveY$uid2m*4&P z{$8*1I)9wg(TRDU&;7aX>v~^Y*FG|1`s4S2PCSX%UF>=~)v!>bp=4X6=dz6^?{%z0 z%>XMTdm4zTnmsZ~%hWDgn?<~jVugD&9=!W_<ovNd8{03yF9f48Oxh;SawQ*23JW!# zp){YddC3HEI4&^YaNrhwd@m`g%daD!A1M#M52Rp%tn}%NboGYqM=ds5D{X{`Xxi1_ zb=BX$e-C@K;zW(_RQ534VU>!DoRY2k)MJC`3Z@{#{?1(Y=)tb!zP`T5D=M%cSc)TU z(G1;%LevuQ4nY)X$!r9G2-hdbNEU?X;7Ac2;<o`+5!$R^$BaZ2k^a!7a#7^@Kx9)* zxXBvgU;_x&e58O6)YQLWnF}O#7(b9Oej>tyDS$vf<SUe`ftz;ie1WD4fHL3<LVcPi zjP%H<5BD6z(oF~JlJqi+D!5$1J>|49xV*`<PIBH9`RY(zCjq_Xz_PdkG0$K%m_(LA z_mhJX0Ovq^0+2kQY$5;HYFYUJmc%HPU<m&A$ib|&MEA!A!M!X(xfb4z5_^#D4imt( z=>kd~1~@ej71;a0XeYBP6tph**AU~9L9K#A5KPV?doiHIL;l4gXqyB`a7#2`Fknkb zgS>*Gn+AnNUIQ2)3Iijri6I{Rg6Z(aL{<ghH$W^7$Yy(KYDFPCe7FOLfH4OJ5^K_O z>1tRll=pyMS`r2qD#-c5Ysr}&w08sI!c}MmV^;xaQaD7S2?lTHM+~e@!EZpofb$B> z>fjcH#fJm}eFwV_%0fWzDFOUMBly(+H&lV23fb%ILiz__rMtuwpgT)oq!7UwlL~N| zi*RDada586lWnlOLj(r+k;wmV|A%sk@f`$@HQWPG))p8rj$QJAQ<Q55MvYX6oCD<( zermBC;(iO{@PheB)#6i$CIBe*$*KUJ01B|eK$`G?j|AARJ%+;IxCA;YTse=z;{MP_ zi$vJ%^|ai9M)J1UqQh$5>L*Aya^LF}pHxvf`YE@R!PlU1PQYIjAv>DFoBN4LaJO0O z*krQ>(B-%Vje#j$!00*cEjw9)iiywZs33nWJ+-<0#|v?HLO?ZZbcjTrE2R#FlZP8@ zDg%$$54QhDn;z_<%vDr<UqNeAF_V$HdcF6w3S=kAi)_(oBXw*{G)YL?w?*~)Z@p1@ zKMw5rUtq-&%mwMh<qhyd!|Yu6i!mEV<IpKyligRESSzvID{1^ere@ewd}5-S`a%s( zOk#+JY2Kqv5!c-F=VGG;Z`kCuCNfV;R@b^xn&m~KXz|pQv)IY4)QKeOXnhsKAtOpk z`#@e7gXKcwhR|mC(a;}N^D(&JN_ReYD#3rU#+YTq7|LbLtk;k_c}^v3gDqnsuVR}2 zpjCXcxv@ZX^CPtQq5QzbChD94MMR=ZN2ks$&@U*jx!#q^3qf-xl}W!BeKObfXtrEG zygw?$BsOF2E`y(gTX3g%4|P}OCX7v&3ta}rrWlK!PDRCLD|Jlap*-#^6$B!TlY&-V zy!JM$)iF}rr{c>mMYjZuE0ex;QFtq;Vy(b!bO*I}Ec~JdZMKuJ@b8We%*FirXwfTX zC0`J>a&3QBm6%>RWQ|kb?`i$7xw&m^*dr2tVJl+f;wBLL{qPPphl_j1N5e0P$pn5c znr}>Cby38>Y=j@usG{B}Qp+^8*_}GMqOwuNH8W~9T0EB~_<|Mrn05YpqVLXdRv@RM zb4NN__!%dfV{*%rZXTNbmDT?`ceU+~l%xUfIjT|p$gIo!=Kj~{fMMkTj>EFp8#;}z zUo*Mm4B-<z?{z)HpE2+`WXp>p^Xx}1bnN_)JUPGA_ZiXeksb5KrmXn!_fPh1HFtAa z*4+}H2%7+SM^)>UM3qm@+W6KH#gj}?XBt?=N*N^I%cZ$m$%Tg*hJJrK@H|DdP?f;z z%@+)rG`{yVFiqche>TOK<zDCEX!okgcwx$Ecr|30GvnP>S()i97i?m1&QXN5S(e5Z zi;00L31kK_;MmVw;+a64P=#%6L}8i64|NvwbaNi$a}yIp9keqB$#sP+p?=^eQu2|K z!zbO=rrVkVJ7%LtLBYpv_0<_Z+cYoTU}rGc);OLK?PA{HXKoiJ!VTv>;zWO;?M#Qe zVbx~xV>+WIT6~XSxVZ>>%_CsOplT42G+i?_BT*XT^E6SoDur(3ko2f#gwvV7c$>+) zkS{9}Lmr1Fu}0WYk0lk249<N<lc9&4$KR?eZ#?2o=7IH&0H@F=-`4U{|JG8$6Rbbp z!{dRls)oQ3;kmO6&g(40;Z(2U4QH<xxoG(~i3;WYhP(U|^-0YM)REpe=&S)pf`+Vw zGsx>m1Rn6hln5~W!wV0bFPe}LDndBrAgC<4r<a3QEd=qQCV@}@4lt0t!4-QHVxCBE z1QNzjD)9sd`@^F_Wsy4ol$y2#-){Y=2MGsH6DZQy13?zpyud9MUZ5DLN{o_%BLt|= z@IM0NP_INlUt?q=VYdyY6Y1cnLZl1`tgIN5jR3(0k9j#nh+uODL=#8|g4+}}E8F3Q z4S_MwR7*&K%58K3cA+!M`Z?4TBHNz-S%sRtp_c|B55gP|%z6o!Uct`LuyG!%Xo_40 zT&hv`fe?UEi-GI_?4kD5fx8=c#?BrEdxQ2uk4_Ot5o^`<#KI8l(&SwTD0Jv+g7{k_ zgx}!?y$8-7gjR-vvuSA*Uz$xJ)rLf+;9LOjH*x}lSz|3Qrt~n?C?)9cS&Q+2h67o! z<$63C!xZd=Jmp@vxKu;HRt^C+R0maK;0Qxf*jlgvMVk85q0#|kiQK=Cvt%d?oV-hJ zH)Q07ge8C`;Wl6j|H~k~90u9ok(o2d<B*+Kk&xL0QxxoLN}>Q{R^YizY2$oyt+%xb z<mrMABy0-R-D3wx5R2{5a)l&=gET{70!K{HFmgk>2$W#BTY!ZCey634HOw-Ij~$Hp zSLM3vP@p3P1Hr`{0FqL$Bl-?48*s{N0wfXa`w;U7lWrWG)M#WR!G^%eD?yh8=kf|* z+yrSN2J0cXove}eK$JP)UBbQ(K~ADTr2&x@_JnxMWz1C5^`w(ObXRxltWS@5Vx=9n zKPud<$>VE-s(1T=;*+k{mOpK{57B};rug&Xz}bbszuVs(#;R1EQmO9{%|*jTLd205 z!^?g`mnMoE$YK5)C82Ps+kp3s!D;j9UUzNSOvuHF!qY_0aH4E9KTvN&;oe74<tZ=f z_^C6I(PB<MCyGY?5gj-feq4KheRhwuW$2w-Wn#rNaUf36Mq}zdjdGe#{QNDmUfh39 zRh$*g=i<b4egCk8C$@E{$J+PKMBbsyG*X%()?O8L62v2XTJwYvXVl#TGOzQxxLE_r zToNTK#bxT2*vp10bYTdiK5Tv<lUPt?FVC27quph;VU-F<?1kg`H}}-V4>48QPuYT} z1o9`mk$GS?ef~r7;O>G8$N0lI9-Rosoqq+<|209FEI;u4uCDiuQ?_GeuI!mEiV*9N zII_dWaB?9~nPoh(ld_;inPc~KH}!J6XFEQM25-w`A03sE-R=p?nv<{Q`f<FZG|qBH zN`L0n>8jzo12gLxzwSDH1O&^c4Iq@Qv;;y3#sd`tJLnD45_+0YBDZd3@bZ@UZoRKf zME^KD&cA5i_F>VWW&bPeqaKE+IZh;!wIMYqQ_g3u|8S>3Fn|^o8y<Q1V{Gs{_>^7n z;~8kTifi|ODLv$b(0uzy0blj|grNq-Rq0XY{TIum#_2aJW)kt7D%?DYk`Yhg)<@6R zjr#J#sGV%mn7)<4{tQktj?YiyKf#YJ$hK_VLYW!2;ZzfU-*~oQK$+#xgdsEm-=%)t zHeUJBqTXbhxPp>yd!v}$HG3idlMoqN1pUUMi8Z^o*dNp@?e2~|b@`pwtpkDqg18wi z;H3q2VTH5AfKI*<hZmO!fjp_Jn^DJNVQxg=Phh`;f*<)B-ZJBHcgn9ZaoJS<bGv3z z$G?9^Pc;dP*rFd;2HTxB?}}!tF=rCdb1Wqo*-VDp$rCnW@?ECi*?-7W3FO}sRlU|W zx}M80IvOxiu*z^kF2hxC?8kJm%19MMv^t2tdr~-=FFH$iFz<46kK1xG9hz#(7RRG0 zH)_}AE;?LeA7hBx3!9q`d<i}a?Qx;2rGxiBDGWYu(f&jDgDDsp3z%h(FX*h2_jGlg zfI_u48xQRL%gEKhBKE+0K{lQ{{QA+dj7DL<9eMmjRqsx!*^w~MP*X{m7L2D`DPpg? zt_JMKH_KTI2DFUA<!8UHg|bdQO=LH4B-^@Cn2{DhcVsSj;ra3u-kq(CHy1|f!)5FC zWy8wvQGFG+KA^cLtM9doO5t;N@9Ur6-e!co#tRl{f{Zj_Tk9c3nxF>HyB$qE+@|<H zI)zja!c6&pbp*M5Kx7UPSOSo6mS;6Iq=2Unu0SRTS8nOJfmMwrXvItB6R=rIBQ!zC zimrhsDQ$SEA^Za5ct9#@VxWBbk{Xy2cEe&=8hLBO{C!f=#YE;U3gqaGtGtkMbMOMe zP7vg7kX@i{%o}b*i4Xw=3pXHBVJ5GJU1Nf$N~qjE85g=9Vp};5^+_m;jUk>MvX+Vx z-7W7SfwC$R=qG!nV?a?|=C&+W3d{vaZRg*+T;zOumEr+M?t6MDxXBx+-e5#tQjBJk z5vVKRClI&t?5_Xck;8Hx`v781B}W1Ewa@NLH(a!<fp7%TArK)=u3z8$;7r85f|PFQ z;a~egqC6E!!lW=Uy489X8!dyRy7io4odq|pAPrMz`qHKVoVJii1PYG@+)$B4*HZU@ z_de7RqXj7^0CTY?I94OW3fne9+};Eu15znwPj?-pmozVjL_JWDDVRE`VyPGl%k{Xr zl9Y{mpw+fJ2;#sHZk4LjbB5b-m?_HkR@hP4g+l0jsQfv_2xw=qN5SU+Umy8>ksviR z&1zPIf&vZ)#D2elei16dfIm?3Q7=ex*Rm1_5r%kZ!m;!O@_wGKn<dSq*w!jp@OhAk zMbf!?5uPs7V=<b4L;GogN5gTzqe@qsY6eAWN?-s_2KQ_)99T4C;iO)2Ccy;_*@Y-0 zWF-j3!EwZBf;-knFtMpE6{aD{D+Dtp4Vw_aF@x|4Q8!!&e7m5#4%9|f<dl<#^AUu6 zBoPP<5D-LTk&b4``946C!UZo0BrKSL;A3G?;-?6<TikHddrx{|>gELVbtbmyPfd&4 zN>=U32|HQw{e?rLM`9xEU@5b;S@L5E^D5D<?o-Y*NBh0c_kAZ`bAQxaej<>mFY?tH zQ8DILnMh+WS%o)sFBNsZ*@>PjXB2*zcy$_@VM`3}?Q-mD)vhOPH4wTp#6@Z3;bJ^T zk$^kxxl!w7ysh=7u8C5?mwa9gp0lj~&Z&ln&*S;3oo^1{3yKzr6oGuSI7e%5@o$Su zUldl#R&jHx+7k>p_ti3td#l)@?+jyZyo!yA`nvQ7Wx^7^h=)#XIp}(T=|URLqfh(& zXk(H=MU%1k*Ze0<$fxg4r737BA3ojBYR+f>!D{@Y>#j=?+1dDp$P4a`gk_xe2uq%L z?c+A3ZPgV;P3?|fJcpZ^XFK(Z8}bF59X98VYqxoB>`rcD7R-E5B~93HQ|pDZxLc!d zvc9)jth-yp{clC2y}Qii#%85`;~qOk=#)u)W5HV5Sp)j_o)e9BzEgG_Q9l38aQ%iv zonWaYdLHbrAq~}fC1yEn7PiBiBJxS~y%;Om$WytqYX}QgY4cf>*M7Q=a%1wMpZTer zSgh!uf;UQq-p#Wk%m4fr>A3r$sbuoa+vb#o1RL@rdC`x-e>(6LQ7PrAyPZ6APu2#c zugwzuX-#eK=uAs4wy%p*an$y#_W6>Oa;VUeSYof!mD*RmN%H-X%~z=3{&Rh&xKiC? z-34d!-B`y%lwiKmEQ^FS8opFDa$LVIWZ4CG%R`1cca?ly?D97fh+4(plcrULqEhlu zM2h+Kdnc`KNJoN5gd9eyfY>p4C^dFSP?sifbRTV!?cB*^lJ+^iJ$xi#N_VQs=yL+4 zhaFuk{v;oeBeg8{jozt8%`NqO?eE7ubvHn*+_E?Q$*1+Kc4{5b{Zs4VYMf?oWxu+) z=fJtCIG?NLJNLW(+w`^aQE!9G_^t+La6HHqNI7eu<XX($No00j6)z5_@z$WZf5rWK z@5^ucTo#qLU)8_Sa#E)F03?-9g?_O0IX!u@9IwYqzuCfbQi_T23JQCZ5|y`QqGDJW z<6_tT<CEmkvcjT<I(7GQ_p~nY454g{nQEWcpMJ_$-63L!;#tugAx&_E$vxcm^w9)y z`)A*>w8kgbKb&^7vq_!FR9z@ICtops9(0MFaGj7<nN5x?1fvL&^g!Bgzz-#Ogm^qb znFCYARRo&^32Z6kfrb<Xz>L<EKrg$?G7I2?z}*N2eGs$3{{_%Mc=D0O1MG0&bpi`1 zDqKK9Jv4$=!a5UzZ*W>wdYHh@HWpIa0GC|x?g>g0cFa&6un%Jbrw{1miZF1?eFCuy zz82uF;35pZ>XN;&CLm~{=l~<Qx<&El$w;eEDd|mDBO_wK-SMz`JKSl2UJM(R!u=n$ zuZEyJ)MM5GU|DmvFEnQLZ8!z3KV7VYfH(&Hs>nGPx*GQ7M@#(lAQJ-n(WRRj{DC1K zkCgF3i4_?RJuu~CP?i`7DMD83WRQYnmM1+k!&6z-3nvSm3-;D7CoRsJf&uFd)Cfd= z{9@9(F&MVms1T2sLiO5fdceJb0OAI7nST=X6qR5uTBdaT9i*;783dxk##N9-1S>2U zGQqn5o<1lAmjaI}Tm}$K-O@@Fj@9n&65S99q&QL$6MT&hYaUa~68|CSjnWfXIl-ZT zp(nPS)RHs@%Fg8wbt#O;vit9sn>5zGaWqx4d>OOub1XQPw4h`h*@OUK8cab*3Ij>H z^JV3b-yYff0HOw%2@<gF0clZAQd17;_68iVhlEV1CPa<zNuh#MSO+pvGNd5eU<s9p zQb0(F(ZswtFLOc)^*-M1gp36MYeG!n?ADCfgNz<4n+_FAg;|BR9Xbl16*%64PiAgg zrP%{&o(9-w!FL3;CJ2!Su7|MlTVh7QH42Gq096+YNY|w#HJrh)&X*d+pHPy&8VooQ z?-*bBoa_tnlz{y%(gW92g4%<DltLmvaghdK7{`%Z8|Z}qJFo_gHVFX=19!6eIM93$ z!#}ix04N37ErBJs2Bbz<)Q~^HMB;f(>BD?#e^$SjUad!`@|ULU;?CZuo?E0HYyx^y zoNueQl}IeRo%wKJsu@2_qzt#-C$%)&c+wUcjairFD+=9(H!g|4GjM~CwTyL2h_7-k zd5>0r?l&-d7cVMy8sC;8t9Q{VbaG3U*NaZ;(b_WcZ)M8lPD7UBi5gBLZN7fOd+fH0 z+F+b3b(T*aTsH8hIFB}6=BeP!DZ_GuahwiZcIl;jw=ZsAt(8?59)wqZwZ>(pVMT(5 zR^K6pQF_PUnXm6ZRowm8S#|Y2(SEhfrF{XybE&s0J|ybUL}TKa$Aq~ZK{25}6GRJM zeC4jiUp|lHtmR0Jcwrok1c%d?qH%rE(CqN-T$lY9PDJ}diz7=>f3ubD7*T#;a4qe6 zF=eAc)s#<JKyH`c2+_YPA$LBiXbda-h845oM6B7~!<lVeqG_yfFoE`~HSiC=>YA>i zn&r6?ol|Sx>b4HdhE~L`zRmVXyjzsp93QDHuVH1TUDOk*x$D%$STi#L2P+&n5%8z$ zUGdS#w!s;t=nvd*>Zl8`WbB-Ktkfrr2k=XvN(UqB5`zNXmL_VIZ0LT4jar{JIBV#v zi@z3B>c5yEcr~nY@^wYazYwjYZ+oVsW-hCwu;FI$&TX&aV`7GWeB|{TPtfHPT>3A* zSrH#z)co0i+N@&uOHH3ax-8Zg|ISZk)n?Usr2qZv!1nLG-w#EV>>XMe*V1X2*QNV< zon>9t<5q&-LP+W9>EtT*kMauax5b!kf-6|jjC%>+NzG{JAYSxY&N-dvTV*G>cS6Vs zqhozk=IzMO5(2V8FiniB&+_uGEALMe=hDjV489so@*0k^;R<OykQqN?MQ@1;Z**eK zdPC1Bm>!1=P<PN#XE?ut!cq=9cvMdB#IeH3zx6lOua&1xcQ}FCMxJl3CzgbF%+wl8 zb3VhDExF|GU7ytwFhvv$@hiXYG@AR^MUP*n780h`-}}o9z<SQ~3%!Zs$^RU6h(6qN z@%;l8^quDE?`Kt2SBHmKZ(CuQQZ`!KoTYEA^WMw*!aao@YATip1lMk(g;cOvW3!** znl=N9pev6h-x%TfiR#O0G#0zyh3nD5PzRlU(nC&7eVzH)hwC#nTVBanzKbf{gE|;= zC+S`8eYb+u(#bb{u8jSBK3y@a*Sk(-E~BWwbCh*3>+$s*b6wQXFl`~cGbh_Xk8mz_ zc!D~RQ`O;KwJ`g6=*RazM3Kl6$Dg1SQzsr11u^=#lHz}IEk8oA8{w-XK}?8eo5PWc zq(7Eu2?%3p1?(!|YOutj{9m3P4i4m3fLR9tydfqrB=i8jkr>_Gu-qqmJfgss2txf} zD1mn*@?Jus_K5n2yr&^&u~7~9iKl{qNh5^<UW}it8t8?`U~@@X?vna>qb2g50q0nO zB4j3D#UcS+cdO%v#>k8E6j7=8&%E($RqGadca`tLX9gsP7k6OA$Mc1@dd~FfG||Xf z>Qp#+I>N^Pg9d)`d$iyIn-YEkH@V#e#`=XZ3csDnAIDR8=h7|*%&*q36gpH*t5o)a z>qdcv7INdrf&{pk+W3AQ%n-(9l{j&);pdD7#-sAfN6q$|wg`UY^PhkKkhSP&xmoj- z)k|)`aGdc_3i|f&rk@q$NqzE2m)OJG#c4;e*}7*xmiKD~v>O=y;+?C;8IG6ab6IK0 zKh(k=Jm6N+xV-%Yu5|uF!3u`+9vL`gQgKk~D+3;C74S%bm0cO=Qlk=))q+)WkmT~P z44QiHxlGNH*TE3xq=~0!g5+qw=s5a3sby;*w^ZCjsvLpQ+J!Lq4$UiP@INyI^M$88 zU)*vZ-&2%#`ZaFWWq_NZ%6*CFr_gxuXu&gb=VFzW?5lO=&pIbMDySn9l_K}5rbDOh zQF9)0032FpBl^R{EsopZn<|nBWz+qP>8P93!N~odDpDJ3*`iv4_zywYa16H4S(I9X z<}oAa<U8K2eTUVTK@d>!oDdv0XXG~bLAdd6$ARh9jGrC&m4K6HB~aM!nY{1#z`nI< zJBB`^=L^`BE`7g+nwwC!wow-FK#_i`5Jb1E{IaBuE{#`k`ZkmlD!|@z%m$w7y@%F* zCWyb|#X|%Uw?6Pog_C!Hi_!a5F%L}^+W94Rk&Bhx4}Fst3z)*De9>h_NA^LF<>uGi z-Cc_9tEP9-evvAL6Ii<mys(NUp2Be_v<yXV{O}bH@W$~AOAy7d{Tre6{WcB$5Lp3S zec_q$8y||3C3~i=wssCbqSd~}i9#4;r(qQ;+m6DH7W?a^HGlZMvWU9V5&ycfo?bQJ zqUsZJnd!_`gvk0B_R=5sCrK7M*8}m^RkJ*IWAV9x3AT79pE`enLU8wXI+k(n`sSQ# zy~T59(K9~LzQ3E>+EHQZrji;!m;iAVo*yLV2j&UDydX~>Onh);qrh?t2E(-*!OQ?t z5L|74NH@N%Wy40M&#yJZhWCXyW!>k)FDD4o(}dMT(j$kPhHI5ZTMU?BY~n5A1j95c zbAWF(^DVqjz#=Tx5jaP%=#@~<<Do<x@M7u*ux+NMnKXEv^dWD2l%k~3Yy&ZXA1(R; zNcLg&?x~K=(f-}XjDH$2rmx|L(xpRV-gtT7Sk@F?4o$d%J>X3!tNdkc%nKago<c7c zxI<cX#+$}d#_@`1tc9!rz0++6!7VYN@7GTZ<agy|bfa=QW*YFEDP{KV<{Ql(<CFZJ z>|ulGz+cCl#yXsMJonSRr?+5Gp^=}3p)dtQ*wY$HT<#<BC<v50AgQQSY!a}Mfa3&I za_I1Y)}m_2aU;y%t4LfH21*p{Z^4HP;Vc#S4(^kY0ynW9Owvn58<0ULvgqyxhzSNP z%ueS)Wr58p&>WH4^SCHb(RCs41Bphk>Ri!)jQmRA$xJo9KWp90XK<@%{<Am%J^A=E z_3d#jcar*!)1?k?pWl=lEQc~xP`sBwY0}6G{C$eR-Ha6vGH0cueZLi_->d%5E+<+z z#1!SBMeBV=Uo;=ONESv5N8PJ_SfdgzC_Xs(vi$V;#r((6R(9V;G(#jmvitQei@~~1 z5GdkBky(9t+<R0x*H&RIcr{K?CnlcBm^{P@is~uw<FYa;Je#>Kwlf?L$|3(UbGEK{ zLqzA?3Nnvq{HKu`SoR)&BlOo7^*7pzJ-u~xlh5#T-)#avwT=AUq(|o4sM1n<D|4J9 zzhi~djKi}BFz=3zlV^#dA(sJRlwS~o_nP+le9&dz5Ig_u=D%^pa-WqcjnVz{oUD%h z^zFTKzvGN~Lfpi$0l7VEX3xT(nJ@!3x-8I;dy_{3`0nr=F{YyMBZKlEjEkPx?z(o` zG0$rEUswM9y7*m%*5FS0#IGC)xp}1Ok`3tG)bIgcTi{S#G?h}^9=UFD4C0;)u?wv- z|J2=sr@e-n648QQ8$<6Kq%97i>bqnSSGy)sMFy=&z(0_R50!d#c=ds+sHYn?VAQU9 z%%zuJA_*26iij!ay2^c8%O)ys$?BZH;r9L1i^M+{7mIiN=C2H*4)Mt&CG|#*^*+Zd z<l0<R=L^y}Uu^=u=ypj~w-3xdqRrOReyLFY=@|X@$=dGJ?O<e(2~|7wN;_knWvsDy zcwoNB_=BhCZYnoR^n2KNcIWu@&7E0!IBo@FKGESXl=GL99&gTRMbjo<-@G)iB~84S z$-RMP&%7_%cE*|;PV}ED<-Q@54R`YUTIV>0OfJac95%VFtzNIe%tA8#Oz3*W-L?<b z1$_iiFS3NQ`V{}B%fIJ@cn)nee$M!J3S-z4FZ|VVUqM0J6gRUO%aur5ShT#X=RW2` zn@|@2Y{bo__->Hx8hu!_$sp{bsdKg7x6Js&7fP;IS3Thj%9o2;$#WB<fdVeWXex>^ zQPg{A$FGr(3FK}%wVqCm_tYu4vHE4aWDsaynwz8~SGetbu;Z^BIhTOCE^+NS@o0qC zsPwk~*5Kws7$PBKyd&J}y^f;d+4E*4CoykgtaL7T{)zKDjy(}-T2de(h1ulVt9P>| zbZ^Pl&+n$BPu-MyKk^?M_uFV-u%E#@2;EN$1K)S-4<<1ynEB$tY<rJWy7WIY!?@p$ z#$y_c<10;Of(h&w6ya$bVJBMLTpBQyfC>laJVIQZKZz6rLtGRtv8!Ms2dGy_B#Kp` z?-6dbAmo5q6fvnSc`-mPra^cRQe_V)5kQ2wN{8hb(h4lFMrNZtgsurh#Xg&jK&Lwk z>pysftgk}=ZP2tO?V*XP9u4*YQ#IJKL0*m1m68OLVweI3OogCOs#SM`YK#d6L<f}S z#(GBJc~dmbG?UkCBbXr?RTa%9L{}^}(l`b-f#1jVeVY@S4kQFN6NP=Qfg=69-CK6& z9iIAz7S%BXGg#4JG-YCp1|#or)7YO5lwYOBvqiMU-_!k36OTI{Fa*Uk?qC{cQJxz_ z<RnLv*nca#QKs$0zwH8=ZT^#A)827Yb)rg`#&2M7^5EB@#gDN8zmDZuR-EFx;P@*j zY`)FIT;ph#mqysio4a^KO1*yIms4HcqGE=KpC-)4^&k2k-I&oHW}aDJ(?zPX^ZT-x z7358tKm)4bR?3sZQ7$DOjmMq|-sKx`N7A^1%sE#6sy9(b*8r06GEf3OK{cf$u!0ax zbtinAp(z7Gz2M`CM3j-HpLa4P8qZMK^^}n@@_fGWNX@`<&IE947V*45Ec<ylb!id; zTZpUR3sGcG37}H%w8)xm?hQ>K%-zqQ`w{IwGo0$rY!%ls7wbzd%J)1r(|Yz}eP+jN z^zC_-Dpuol?R7aF3p#j#BSW|qXS_u<oAK^;cLno_d|<b(esW=oUbnU>JGEc@DW988 zPrXfT5zifT8r(L(DaId(N=BL5hNjN6R}4(m&}Nw8pZQ<wuG7k)G=>wJ#^W+XzvW5! zt-RmFUlP>$a58t;cvz+DgiC2r&v9`J?26c;NoIi9E}&1Pa?~1uRsj<+avN~f0OS^X z6_)OPml5UZ()MaFUIT&Ab#G9V=Q39NyQdsjiakSf8*qT6@YAnpyNP3G;Agh#lRL7g ztQ=##wzI?eX})986ee~tE4ozp*Xd<z-u=5yeuY-44U8@Gg=xYRhHwhEy_uK0ysAr? z1-;*7NLUGN$SgXJJvu=wo0M%m#NLmabLgLSX&WS~tkAAI)0e5mC}(@2IV?3{CsSOL zFZhwxmAmg!_xhKyZlxVNsgsXr-8F;*|J@hBXC$e=i1e3gH0z~Fy7VzRb(9kht{d^k zG{ad)b0t*du5Eet+VA-*W<_46R%gP%!XjR%C|{Lbyj@4;s!pVYrqfkK{XiZuBte6O z5)ph8*xEoL^M>#rWVRrE{SNGt4?5@QG^X+zdv+n3cRDZvFMdtqe#P=iN_~Z0Wg~U_ zs~JYq*@U^gv^%YBEyo!N0~3q9XwmNoWH@2FrOg~gvyT$&9u{n~UU^lH*9R8>CcH?n zfkZa~_c38!`Vvcs6D6TVviJbs*0ATyZ=|w2GkhAW9>*D`u|gPg<^<k-Y<SfBOQ)Fg zviQYw4B@%66}j%GJCE>T71zk*iqiNGv7G0`KzbLdn#oJY^Y-Hwtj+MHdUYK)`ow%Z zH;e&)`8P5JU!(g6{sb>R#R=kQe&czMwpsZv|LS%-FWYM>1if&XInP3Kg9!&G+<Vo6 z_qJ}AT?%Le0!$Jd%dp#!2GJ50CBU!&YCIT}<EsB3O9%a7dl6A-4TxBvsewv{1nI$` zhqx|~6%yhD+#QFsbZCMh522+)X5M5UJfS9lT?T>723U5m(ZV1xr}<Y19|9J;u-}4L zqbH1#h&d6-qN3och;+q3L^HU27j*oT><@E%ruM-+Y5UulFYPyoH{BwB9C!?UMTT)w zGczmj{1v#FF#Y6#qgRt+8%q8o8;k$g1TttJ7OAiY)T*t!uU9IX$xjOy9Lk8(dVI~^ zVx^k-#g8}sQdYt7M$%aR`E%NPHqOU5<Z**r#oxLDn62)KXP=!FP0qGzZ+qDrzp#j7 zISlWpn7UDHNMvLMf;sIMiRSjg&FYKo5Dc_;K}=ep2Xb8fjQ(BtqG&6Nc^HJ)VMOU^ zqEoNxMn_YKee>;fCMhDk|L1{+)}#{@L8(oL$NdxM&EFMrChBp*$$`PdlvAj(F~LW? z(cq>Ry8ryMmlV?FJ04?IyMMZpX+Rz#9`cEd!8&n**nwTG+;95U6~)r0E7F>&>{Ym5 z8I1A$(YsY|P`hbk0-~Ug8Q5@wx;FG<X0hC^kL`z!aH`pU_4$H!wxS&;T|f1cbBNW` z2kOgX517}c32WjQQ?F^p`+4T+*BERZ`)(TVThi%kB{E3f2dT%vKu2Y_lJq8PRO~v7 zmj_}#1#N8s0;Fa4LZH#z+hYS2*m&FayN!#_eef$4R_1s&*)D&!St2Ot_2LXz>sAyN zj>p*L#JN5O9!CJ{ZWgo@L^)au7ovUZD_Wg6@l1YLcTb(d6Ftlx3)A40E6<-fD`i?x z_1pfqYzYY!_FPHvuxXclF92GO&*rAFzt@-Qm+0wXyl<3z9A{mLE*td5adH{VwY0rP zZFO~AgBFo6E^W3KE4~;ZV;;Kx;j6b#<)ES!c>E?x8#Q~NR2yglodl6|{``@Azs5za zZSS^ie{<iuod{VhZUciKo+jqvoLxU&nSDeN)MCXJsm<?dq(Te-LUio9Lv5M~VXxE+ zED0?YoBe<5cKyI6Yn#}&SKl0Nzw7w4Kvzc{;JEOpghp=Nz9VC0NAqX2cx0F&E)}2G z%KvDY`&JwRKk}iBnzaT=iGU`BY$7W5&Cu_NH4h=@p&6+l+3+0Y5!C77aOrxMnuN}` z1MBbS^CxWr@=F8n?gmoaqsHm7u}_C0(~lHq_6AlP(Bjv%9kPm*B4?j4np80srkiAL z1Ga~!tQr8QVc!JAh^77_ax5~hAZB{xAF%f$0S9EK2$}d+ByorsfR^NQaJfSw2n;$% zmJ&HbpdS{j$0!dCgoCwIN&+xvph-b82zkH47ljeX1MH}~U_t>^XzT>kxur=!S5<YL z&vFyzrLAr`;@N?F7_e}fSAqEm1zUxA6zpf=x(-kfgu)0dKSjkCa$3?DM&!2fW<SDw zd&Ts%;SVct3r7=EGcUNqFe_-Z;r$}qo31e)4;c`8I-vzAxH)UEelUdOG{Ilszrgci zl1_&%B#3VT{A7UmxFVoanX+I|#of6>;7$|T;RPKy!9hH$#`W}8ahbetW05k8I=_Mv zrN@5|?T6ek69#&Ji$$`noQL^*k(OW_PwrKw@Z|%9T6ebX%W5`n9jyze{4%Kg?oKm1 zeeUu0Zk+wJ>Mr!`H}`6#uaSAA;Vx2fX<(z>>fi%AW52pr&S{kID&X}L>tAAbq>0tK zRFlxEdDBLe@p=k3n#^(~&xhc~lbrr+Q=PpM{h_@0q=VA7hu}M2cF}nkw9uj;n2Xp0 z#6FPJMS={b&LJs2jZz^dHi3VP<ViC%B^w;wr&_$n8WShbf|u@Pj4K0Oxw&2bQwe?* z`jmsWxBfZ*`bg6JU--eZN=c7)^F)f#ew+kKFUhkh;J|ygJB?mOC3e0M;h4LQrA}*@ zqP=+TDjdgJ9!y5Ur}Ctv6NZA(*C9fRZ(p0!)Oz$XOtN(KA+k_jJlc}gcXu>hUp2XE z<~41hg21uIUTaHkk$R?-z`9QqKEMj;5X0>9d!)~KAMKl<0@Iu;g&S%k{=wvY%@<9t zaHI&T7~`wUCtJls5$JhK#+NI@F2<~>0dBL?;?J3xRkZOe@?sZ-c?>tNLLLjJ{^CtM zc0CdbhIGtT6m*q>)dDsyOAct?kC0760seV|<Q^0l_UUdm=R!F2dIs;eGKmv0b$BL} z&OB}q?OUts_9L;Ab$#pzsa8XEPLV10$toqOzdT>;<&n?19bKJjNbPQ<wv#I7RVt@* zs?4%y=@d>We)be@u@=YWw+jED1tnOn^X{A{f3C~>e~C&H>M%(jqa8=0GcV<XTsHGF zDZeMVD@ZcqPQJ(r%N<~Hc=bL!YJTxk6YS!U{Dm(*NBFkZU6kH>8r{9JuO_S0EMl{# zhp^JX+kdQoVC0n3NC!T9=ia=oV=7sDm6PTf+<u(66To0=y9O49qWzvj=%ELeZ5x4| z1x2(==mk0u3?NAnjT99jSQ4lgL5fhx9tNjwc@f1W6)dOu4!qld^3TT=%-+h`%kqI= zR$uCT;GR#aRjCxIQ2UcAzh=8UGMF}E-(_%%C>+oQ!tmm_eC`e`+X^fE*$Dx(T{m)R z>@1471}A8A(05FW^C@}kMavo>cO64>pUd;^mHL+}lVpA~Q)k{|`S;O&f;4e+IAv5{ zz}*>8)38?MXRGi7T3kpFJ_)ZB><nB~CV$&m$qD%+7$OKqvI0B1D8Iug4ULtM+nq0% zsMm4PBP9_j;Y3nWSHQPZS!?9O(>NnI9*fE2rom=N5T8Jrwc*9+ulTUpfKK;wgejAk zm(Ra}E!o@^&aYXU>N8;@_(TwoGX>+WWL|>tNOoype**c}e>o*b>m)<qy@+`Jq3;ps z(a6v!3-3bdg5}^+fp{nw_W|S#i(9zPiSEjcF5fSsxyc1qYhYDDoI3F0;wB&h8`yuK z$ryRTg+l!@AfKW8R0H<@^5EJ5|0_JeM}S6(gt(E?9w4cLoogs;zniQ3&9y6IvYNL1 z_b~W=lIIv?<J4BHRCt4QU7W-Z*X=jxd10nwu7n9r)E!0h9>YtCGI!M~>ZZ?~f)DRY zDWmNX+t=BKVv_Hq*sWl)S_ncIYTkBcp45-i)fmb^^Is-VX2V6}X~L=-=3ZpBZK&1x zVG`3wOsB98jXKs0f8=~qCN<SlTOFK}^-8AVpO9<pNDb_Ou2NARfn(gPr(h`~p-??R z`)WOTiFBR)DV4{)GdM{Q_6$4C4eD>#RTuFhN>i(Z)NZF=2bwqZA3AWOlp^}X6!b8v zgcDW!P%zlw#)piQuM~b6nY*8qPx_odHVX|Uvr5HtzXz7JY(XdRizf2KKcYzv5en&& zm`yj!2YGCNeiy$kpZERZo!z`dhA5|%TV0x0JoG+s`|WmxDi+IW`Wc?rXgqFoD=$1d z!}El;x>e}5^Xr~zTWvM)nH&1f+iE<T)2Y0B{MUuNI{W!7+Gvr}^fp36(*qM|Xj77e zEi6D9Hv#0#D{M6q30BilfAjR?#;bcE<z$#-^42HC>a5w*hoKS@4^7l}#J)1Sm3Wl0 zNVEy8%O%zYj9&8goo+K8G0Hb6Hab0gAmfydV(JYYwAh$1yNtH5g3oV!Cld-<B1SV9 zrW&P{ksnQ0n(Q;L3%aILmmTF|U19cAJNAbgzbV3H+f&bnw(iP?)pXiGBZaf5KRw{> z<ha;<vx0Aku{3{aoAc`2`Db!l6cr(v2mU8$jorBHP~=qTR5O<~s_w9J+l^dBMI|=B zfap7w#!tkR-0SW48tdr~8JW#pp0LT<;_~0IP;IhF?qz&LRH*tZnc~hmudfT0%*=+B zC$hD5GFq-5H?zED4OQ>42&6C6#JNHHMwG4fQ|DVMU$11U>sS1(l0;!mP!>T+48aMO zqfbioy=Y5xqeDn?-S#sI(6A*T4fVXS5(?6r^<-R@m89roso%LZ=*bX84Geoa1s1E; zd6~wB8YL|j<^5}FfBlF(c|c$AyNgn{qP_QW$o`bJH%Ngmgrb2h5UcQ9*=z}fej3oT zNXG+|kHP!`X_{*gGzSg`;+BBLG`<EwXu;~esVET)TgZqL3`PV9mLfL0{{@x6sqMEN z+)+?f+q@pYtibRG(A>ti$R=C@@#x4R7#4(DHU@tPfL|>IW`d5!Rzq$G#-~lolrVD6 z4l;nBkO4xMC6cZJUI`|<y@hoyl@l3P|7Sd9Ip@dc{s$eeReiRae(au8p|O>F7^K$d zfPAc|mN;c)QQ4hEV^7)8hV96_G3taCd4ArQHx&$t1{$txDzy|s459^jKbPGkPDPby zPo6Q?g*L8F787v1K!)JOxq9kIBksE2d;g*?iq2&^mjB#Ak2Ek5LJ;OM_;mX8A$Ea7 z3o5RufXq!Gb0(<0E}kAP8c1$!!ma<p3gjf3-A&+r1)^Zwj#>Nsx#v;4%O;`TbiEV1 zq(Zb%DjEf8s6?66-t1-&g@IzlWpyBh1}VG)$y=Yk#3q3dF2JHy_P{!DA0674VSD)n z0&%M`5-S^eQU&b>c+q<N?bq0QRl;SDeF&94;rvr?!e7IVEt4Hs-__J~60m{Vrm?%e zl@;!#^xOGqf_oilX6~^gk6{IK(c;cyPUFugA_L>`%koDWuH}pW#SY$Sl+x@8MUnp` zh~KVmLo^TZN2ahRU-*$R;Me*Y=8B_|&dYGDop4Ok=EwA_em$bl6Ugl~ssYlz3mSPi zLwm9yi#*#!rrT7)Dc8$t**+76<K)zcpn!2$m-cg*A%UXu8*!5d8RL0cq7eo~+$w6( z3jF4vu?{3S=+o+kmL=qx3iw>a-JyZh3xnwc=@5;%1|_4<S11i}V@+Q)Ur+QK+p3J` z9#rilN=!PHne8G_2g^b=C*zwNtCDV(jaCito=MP4mY;oPwvjsRja&HrPv9I!T4|;` zydS<R;(}<-LmYp;e(SERT=V5IDK)b$bOK)*s{z0cx!4;KG7_D?7UvG)2Md{V@%b_+ zx6=5MHXX@=z9tZ+tf}p<Z{Bn>Nq-<?Ii#ka;{Urj3l$t=S}iZ0B<#Xo;(TKVW;xtE z^rXl1-BADu$$*m-N*|E+mCq3BMc}5up+z=F;0Fa!VE!cFzmRJK7*^rmnOOX*xGg?s zF~gu0$4T!}UVcl|myxpn(S9wx^2rSRWIBx-mquS6G}BmF8{#xqSXwz-L1E>JZ;df< z<1D*?>=mW)N<Vu$yq+7+&eKwUR82M-@@(KU4khMju^MwhkvU)DppqiN--h-c4!KDk zjbaR*V+MS!vMHaM+^I^tcKAK`J{T7q19&HBZ4T5HYp))DW!nT402_@v(EcP*#-de0 z;d5kk%vIsJ-*byMOIpva#LoZp9>WHROGWKK99#RdIhcwqzH#J8Kv;s`mz=6kHCgew z#rnQe$|MHSuPR@ZnI`&?&&y--Q_+-$gn(b+G-i^)-VGOHB{XCqWgY@las)sJQPZVR z!%|lH9=K=s0CfV!QFN>?*s#ibpiUBiK9Dy7ak2#b!$aIcC|q-mMG95qf&d2?3?<Xm zNFgjhr;z12Y|atMZXXbV5hoFR-w{Vu5E9^gCo#JPcsfA80dtKc!Z_V1YnFMgrKGUD zZ1mS&$xF9Pi;AvU8=ihYG<d6uGA&uW!py=#G9*UgWcFuPm^I(E72nIiUCImhdhwXh zl*VbVaOphpJTKPshK^<I88huSGGXuT<a37Pm+iA`v%kJs$!oYl_lL~OQ>RceMziC@ zsnm+Md6~yAa8DBiy+waBeyC+cY08>Z@*t{YV14T0tq(IOt;YoF4{PJO1j?fP6>9oh z8V@21Z;5_F^<c8FHTCDBLj8vK0SO?prwKkYj1O(G6n|xko8j2oxvZKXXkf%WwZDC_ zs%2+oZMKU;;;D3;Utinv4(+d*aauNp<C|Pd^>$~kqvsaKpLUJ<aO9HtiRNoQ#zba6 zKm0_!Psv`?_O+V!)HW6B4c)shwwuSSmaX0xxn=poOIJ#K{{-@x3$ysU3<j<|^~lH_ z+F|}jEdLi=*Xm0;W2DrO(qX`fIm>E9qAn}IwG?nev6?z>lw@MgZP4r1lQxMpQ7TA2 znT;{`XyH?HE^V+iQ#fj&7%Q>oH#*h7{=nluu7~9oIT59><U)Du^NiVQc74FN?I5B! z3r3mZQ-AL|W1*&S(ZW{e;VWC6gH{qCu~?d*P8+1;_9WhXb*<N84e&zN4Y#-8kMz<F z4DENf-ElO!)JFWAXsdX{J{nxVR@o0t&CYzvl|gC>fcpYP3H$V*RAJl0sfyNVr!wDL zzVEkWWt%~|j9cr_dZX~x_KcG?drrd5Tw!JCC&k#9tMj{*++5BmD5}Y3?O*ExAZ|5{ zH?}LK3y#)dLLrQmpcx}$u6_QY&Y_O53ynXpnb#kc4c<@V%`!ykcBE{gUz=TFijR9q zlmd9BrPUxl3MO*}uxrbP-fM)aDUFcO$=_g78de!fwztOUDyE;rO@7qx_q{&fX+T{6 zuxFA)o=FhTxe>{I2DFBW%CC>o4pTLjf08!Yun`(rb|dw$NJT~WQvWTa#g^hids;!> zM*3-?dS=Pww#3%@U#b?VbOQ$faJA=6kVY~Ta%Bc~8xU&16?l3n+6>lsc)Cy!W(IEa z9<X4q^a=y?u*q_GmV^DE24;!-ACB514`?fddJ9HV#KnCR<^?4cWY7l+%j_=)Ci&}D zw$X@AsS$V970ufx&xgwhJvUDP7uudHq+vVCm`xh*sk;-q*omi8nkpQ|3Fdnivy3@L zjJG>qWSTiGj0gvYPf@1ED6?af5w`K5kTKNV>A{>iGc$zs+27j!((un&{hfafJx;vO z`j9Vp(0RLRvwh~vi9b1&laCxp{l&!oQj(ikA@AtstovIcs}Dt;hNx0Tysf(FgAxDg zYsUM3CTEU%d7Qn{NsJ9rl5`lJ`{yt{`N`im67Tje>f=MQI+Xz2F4-MaZVL8L@cskl z7EU&VY3$*29x@6TR2*EOl`?9lh$*DHlrhmCuhJ>}#WdP2jyH`@G>7X1w`Si2g-aCu z89@tQCirKEum5}~<J0i_Ep=Yymu#976UX!F0y?py`;#B8Y^>?%&CTt6eM+{&z9O$_ zOt_VZ7f{jMup<oKI~%{QaHHRvKatS@0at8MB=+5%?jjGj=24oC8FOnGBRlug_;kvg zGMV3sm_^Rmn#m~O7Tqb;hbq|ym7-%e4|mwt>@KFx(`l?OFeDg>2&p1hNM?2gHYZe# zO@cuFnl^EI3x!?kw;Cmve57y@5;xLmbFLI|4vp)Io;N0xUp!C8K%>Xfs~r`(7lGU$ zf%{oQ%~_^vBwV8*cDJEhT2`$#j!?yq77xv`FLmRmPMu2vTaeh-+Z*P(3Bq*)Eiw;Q zWgSj)>G_<wXq~gYS7l0TF5ftmrQ_g!FE6KvdQRrHF*f`}&fj?JC$FfTJFBktcVCpB z$UgYCdXHYDce%a%d$%q7J^Z>{(oAl-fL&Pc6Kt1#2cUViNvt2>TQW86=iu$DjP zu-neUQP(lo(N106q4%`G{*=RMts+i-nqWUpXrQGk_`)W4=}ViO{bXqYO^=Wv0(w3m zVV}d_#GC(z^EH<&kO)@17<82mz1!XK5IUz{%~UhfnGMYv;IeI~Q~F|#*EKJ&-TRK| z3%(INZ#Ic$Y;Jm<<KAbAxe0#lHBKYzRb48uPI>qBij`h8yO#F(j>aeDl`j$qJGXhz z^+KNvS<|MpM1M*t{1D^u*Xa2e712*Sk%^+ok^0NG-M7vC{3)aOuqS{O8%>_MVvLTy z5E>cob>!md_MTH+=oQtNpS|ujmXV&4`4?&qjI`Uk>zXk-nscKPe6z#vXWD+g=4j`x z{KJ2v-Gj?pIw!nd*mrf<aDNm1d$*2Je$y#422`=~z@jIfSzBm+-AYCiQk^KN<IuSJ z#1a5%(6j|POT@~CRF8P1B3N-igM$5o4xOYSC{%-?{`|e?VmUA-4>6DqDbNA7m2l;e z><>Ujq?Rz9ux*0Xi9ARynjVM^$4N@b;?22_qK^)hpWP{qu2ooVQ_~=bC?+cM1WZmC z76b|BtooNSVG5=X8avw-08Id{_drO~v-nID%OR>z#tcy%W*1$*_}%D5=s4VE(N zwO4xX8ojh#TkUA5shO@`V)y%aX^C4Cj$^(4&Lx%)sT6L4Z<%Cp=oV*9kE7X_JI+7( z;nsAmCI0MJ$gMXD{$Rz_$$bn?9F08p*?NW6<Eftln1Sitzl|Q(M-wQ2_|)%dqR)67 zfTwd<G;V@T<(>COO7`MUwV?$g!w1s_cl`wif4+?N(@{5Kaujt{>GQ6l)<gWSgvAI; z^^m_l<zWWDbn0Hp`YWDXY@b`d7nm|0_W!nr58SEKv$b#pk00jE{TCT;6$-lrJ!wK+ zU}&D6#@O)r%o!?Segk19w#NUTW~FWF=QV>@OZHd*j~HNA7>}!JA;74yv{1CwUb(}v z;i)FH8>&gv*>0J{GAnMq?EO2vY2q|G8hQd1V@)KRiu%2nVJB7I?KLP4yyCh_Cc87% z$D$-jci~%7KEGL@qM@*|T3XZm>5gX)hTbY3R5vj+$xLa!dcCpf{iAh?-Ac|Trm=5m zqVOzoSF2D&5PptJ^{Ov-JG^JR<lVjbxlQL+Nk_sg2OHcirb<K0m7G1~;&<(_O*SHq zCy|FrDI;JjleH=L4!oRp62sg5)$qeW(WZ!XzaBITBV*1eSmYHS2OO+|66B3yj>d+X zMHFlWKYl3CPoek<5Tn2{0$iic`s`HoDM$aN*J$2hG%JrepN$XPquF13Wxj?wLvk9< zQ1u&L)UtO^1bn0n*aJ*WC70XDNCC%ixzx%S#h}8EdUblYKX?#~hSK#db|^YyG%bH} z16Y=zccKLm_`H-jMPEH}1%sc&7ERFxz+#lo+86CV4E{L%z}y7CZ;M$_y-BMD&(jl4 z;5z?*q8rTP*mn||qJvTp5rADY6e2@;B5Vqf+6p*Cs|_hb%i{{bTy<0v<S=uvC(?%) zCzQG&%vpQwJo1bnn+PZXg*Z5(vMIGTE}^2ANm?R>1J!zV-C!w2YL)?M2c2AS0|D6E zXpdCg#ag!TODm-(f!tbmP(OEUF@hrIl=>IRd#`GaJ{+IM8N|Q4+g3;eZZao_Qg-)l zD<HLs69U?g<<~sjtQP9T`i!Oqwl&*OhCGS=q}lGyyYjS=-nS#LBt#p}RWT;JUzz?L z#nol-b5!M>Sld*4?q1uH72opSECQwJ*jIJOP5e*EZ(_*?=cBS3?ERM0Hxe_Y)qp#c zx#++8?kj^!`7NpajNVHggeEIlRZLdszKJ6`=kGl*nEn7Bz+bF)cPB5)e{ix``3b54 zb^?1PCRE~om=?rTi`3GCvT;iquuhOIP?P(#5vfzTs<UvAF&Bat|3&+TCknf}Xxv6E zn$Up!Vqb*k$Xv|;{~Q6<Kf-1Lna>*C)%NnHaehXVYk&K@;-))LkNnBa=H|C&8`~5I z-)n~MPZ4D>#7Pd~!N>Y!dRO3l7b!bEY7DFT%oZY=R@!^xJ(u}B<wU@$WiYQ|V8M|w zc~(CqV7QBt!Q@V-@t%OWluZin$}e`d?jv3n6TnontHf#enbWSey7Yf^iF(TUvk$Se zZ@{xukK?kC6Ij?rBme0yO{I;T)i)Yd)R)BUCN<mn7f#nkXc-FgfEZ!CaMTqAS0bbc zb>(~j6o(_1>{WnU0h}`#fr!f~VO(^;3qcv2ps~XFab3CILK1EM1WmY;wv*U<D9)4D z6wQA)p*sH(44cg7cMq;TbFMvR>n5L-vO1?WMxJ_VlCE7XFZzW3uVo-`c&8z+yEC$} zt~2?hrJZ`V_Wri*>Q+(-#otrE97(bt@MDIpr8}rR%Im!1s&m%#-W#iHoe42F>^x7H zg?j9fx`(pf@uY<*%x2&WOZhE?`TO#uF9(C(oH?`$tUJ(S3Lk2u`$ZagED)$DfX%^z zumtmgfXY%)JfKye=NJ{MzF>}LAH&UR&<toIo?DJUgcgnv#4I%HZsCzFeJo?vF&uL+ ze_<bG)|%1RpclJN@t`JHZwaJ62IKWw6?xLP;*8L(B^7z3zBmH^9fSrDU7b9hRoO}u zeZwA7kuHFC_|=N{v_G>D7{^q<7m-+#2ye_~B^!h_s<#{4L<<D!G@wX|@r$4N_CXab zTLs^uh4G_wtT;9rrKx6WtDFATvGfusG=I|G);3l)xs;te^XQFIhGZ=2O?;0vdRBt4 zIE>>v*!X`<p$O$msna>e(qL}aRA>dHfs{0&n!vsgL3<%}VMwzAKoyrN#h|IU^(ye! z5Q+ml@Iu(LLL?W6c3%LT0M$o8$p+*zR4IY>_X!4lfD#}CF~B`z{-?!2kt8y_`|2Ty zDhS?&AQuE^!hnuZEg&c%{|Oz^y+C6{axBo53Z-qKs6Enh4<Fb<;XvhI<5tiQa8<=a z?u%{vmcp|p$0HtSryq!oN##XWFa$Nm%xuc+p+9|(Ruhf-x2T0%XKZ-YtF|0UbpXjF zr`Nt2YS7J4Ul;b2+&P|<-0b-Y6EvT&1|^&GW8znYC)|)FH5)M56aVsC&i)fo_NqA9 ze$~SL{DmQht}S@g)rHTu4tP(uibb9JzVNF0)W+mh)c4!#U7z}gyDvKM%dtG1=r&eV zpe5*EJJelRkxFLc4Mm+@f#oN}Q|G2Dr&y%%8+n~td557gM{oso{f1M%wE4$Z>z-fn zR<pgFrG5MB@!03iR?pt-lys599KABE`6ocH$aAe)@Nzhox9gc{7xZ7qc~@K=La(iB zu@U@1lNU(T&yS3LAK5Rv&J=+nO9gH707X>_<D{UbCTXdrbKXn_Y9bmvLdqtYsXkrb zxmCTyl9V<L)c_-Q(bgeyU4!uP<Hxs#-uFMVHSM-glEA2V)Xok&wBM7oRy0g{BV%rM z^{Mu9*<im7t~G8daUdWTXqo`Oks%17Ey&_$s%oa6Y^d6>>TU|}-i*bX2GfmFJ$qp0 z+9}nr9x}C;uDd`6)?!wfG9OyXdw|7>-_Wzeq7pwm&ihh^eLQ4u)Kj9~_X0i=(ytWM z-%VIqs2zl>vPDp+)H|uz(9kDWgQThtwLvp6N>URn)8ME}4VSq3OM92yqug93FInEd z94w2i;sJLun=Ot#oqQ&Dg)0%a&`4!#Q3V<rQtv!H8uh+Sj^39$t}Ph@M`75y+ZJjv zyG&$cT|z!av?cb}d3f*D$Ap<YeGs$mQ)L%0TJT0AB?K_ndw01TKRQ?MR&Gcd)F+FG zWGFM@pUbZr)nEv9jVF#VN^+E95$rQ4trGEJD7oh=kVgjG+pxWd@=)2N#$A_}Ny762 zqoyhpt%K+d_cwstfEx#n<Q4FkLAYXx_zH0>V5PvXo7PI=!yOs9(u&{!20J1&UXUe$ z`32B7sQ-LEc1#JI+$@xnSvDl`76Vl~h?K4XCA}yZj6q?CDq8@V$VkP*(Ow3H<_M56 zN!bkAl%Q7vr3O|XXQ>jQh{=m5@JI9cZ8U*0cqtg12DJENzVJqL054_Cc)W-<J%ayp z4L3iGbM|OdY4I=`&Lg?CHS0SS?ag_huBraM_#nf+sWlbgIiC=Zd_NtsIRZ{nRWDOC zluzUGRjF+bm8bUzny{jAruZuwG{4H0a2h*FLUG47b<?0~*#L%(cvQ5tl-5A68b5aP zNXS;x!+Y1TQ;c}wS`6~^5H)V|pa;abrogBdZ&=)CVDIi^EY6|K6w!F3$|GgdO@&>7 z#dd=C(Scp=HU#gm*;>)ZnX;^b(!FgrE;79SkEt^OhjQ=#|Byr_OA9rXJvk-HiOMpP zk|m1HQN)mtbt;v0W{8p`Lgd&^3o0SW*k|mL?PO;#mXIuC494vL&-7fs>-t~Ub3M=X zbUH1}ec#{v^Lf8tubB}vJs*W1F9;c>?HgT(Q2Xio=fola@FESME+GY@-<U0Usa6$? zRnJa<5&Y=m8Q34d7ZgyCu0qD=>%^34-{n`1P`O7i^uH)v3krV(#e<5IrzE~%_xlh^ z9Cs+uVZ;vKm$F~)yDw&~rfmPQ?Z57n5I>R9|8eV=K^Eh@T_5$>6I_6FQ9&n;6nGi9 z{dKpb?QJacS{If79c6h&fBI<LIxmY;U&wk!tzPJe$!^=f`k#X!J28F%&Cf1t^PGIo zjKWW(v~mU<s(5)xkL|FjriMQ*#jUqem}w*qIk);-E9!&Wxu4+N4Dkq<{IMp{pZ>`= z(dCv@zf;IDZK_^nS}LBq?hw@*SU;PQA6tG@^l)Q)f7Z~z;K{NweE;AG^gEtr*Z}Ys z+y^fqF(!zb2$<Ng(n0)QD!??yS(zp*Ce#Fy6@hmSM$cMewIQT>B&m~38izM}P5g{5 z7V?hYJ&27+Qk$)x0X!g=P8KeI&;*zlU5EQ1Kh~-)wWfA-xu7`3-1+if7VoID-W$!M zZ6+}CjHeD%Lp<AH2FJJNjh8}K2oqe?jANNr6)QNzJns8^{D|Y8%-am+zxmCFyL|dE z?d*m2-OlW;@2B*zQ>Fajen^kYFJz&xcV;xu)W0B`Ji4|Lt$~QY*}iolvp7Vuoc7~; z@Kz;n^Y5~|VRNi#nv`oWIo!$pCf}2v5dh~b;bXR&#l;1gVkL0S3M>vva1A!#MIr!? zv{47KdE<FuL&hW!S)eauIOC0jHqv+i2_TDOf1zh<t;<&@=7@uvh^>00sb=iDUh-F~ z**5#@N${s$9RI!?!2eN5<dN|>#xs8mZ>^9IPmD2p3#jkpqSkGRUR8Hj+_G5VY1nz{ z;)|MY5ixVfXiODU24vmtXNGiSK*fbihVU(Vu~Zi|9x=*%r0wuhhQ)~sDpf<x?k25l zM=^Fyeow3B<y{-5@Zmj?tCt1KD&|*7n4kwA)JnUDrChM(ea|v*xw+7%2dLOARtAX| zLBbZ<L8%ef+CO$|{O*tj;-G3p!MPhIN&mU-zdczmA3Qn9U#3};7WP-OT+JdQRa8J# z0mkF6FQH3&9yaW-HV5LVz}YjSqQy4{X||}4uweEs47dY@mg%!M!0hpR9SHZNAhX}l z<QoFmAjGGkLCtL_hIu`lG&Etg0nsLS?*L675^jkCy()ggAk6*3fRWmGKIx$9X6aYw z&(5BD+jdy7#<}}ghNw#4;6=p`b(fwPUwV+7R5p_tQ^?HB`oc&e6ADJW`dH2<^Pl~k ziE(Y#nL*xN9qXzs+tZ^NSuY0Q8g&!x0cWVr)r2{;PThGi+3;t1?BD?{#GWQm8EI*= zT_OVt2qA^XQl5bC-1tPQ=FburFE8R0Yf^J{$$_`t$vaJMCclM%9tj@->v(ynWyv%C zzI`WVb*Tc*4mHTC<rwZ5gLm1g8%Q^`Xjc926TvTe1KLgM`IxKwkDzBH(2Ete<oXlh zTOBVSdzG_U<Eln>%lGmN3VOcCY;uzL^?~kHHIL$;Fh!NaTOYp`BM%THn!<!?1_)YK zU!UGIwJ^@f&5C6#;>S`#DZn&UYiD=pAPBJ%azJ~9^ykBJV+ED?`1rlX2_iB&UkM9; zhW!YWXUCG3PxO=@i|BIVJTFB!UvwXWXRLN2`=NrvjqT<7r>^BU6VK(qLRQqw>gy-r zv+8Gor($z{vzc*1d<|kiEWUV9LN~0f?QSG+I3iE;I^=n)alCh$G@AFs`migV8S;|B z?VD~|>uX9~_<nnlXpv;4I&6Om%)C-{@CG^Pj06gp)(Kx9pHDT21jv6lVwQ<nC3wma zkNY=c>o-WQG{^b+`1$$ySRP@gtVLZiG5zXx_aBcU-#12QRlQ9jcf50v5{q|>fMn5d zClEs>cXYZ(<ku*`vO_`i*i=u_y(R{Bwz+E90=0F$E-sXv1vTO!ir$J(M-vUb4&mU% z{@{m_foXP~ZSP@Z<xV)KuBw)}-OqV<D*LLG(%bl9nL4rULc*>hUk}7~r%E3;alamR zF-b;R@zc@JsoW~6ch&qG(oa47G+fQ^%S-cubSX~<?`zK7Dr4+KuNhcZ(TC$gX`2F$ zi$D?zj1e&+O%R_I$ibs!!$DsCNy7+??*hnot4|CtM79We`7l5S&bxps`4IlWjGJH^ z4oxS`m!M?^z9&R`Wx-(uu=M@V;f68SU*H3_x-1}y0Hq&jVT?qmx7Wh4z}G@xd1!$b z^oC*q{|2Z&pCtx%8H1%O9=u0T95;4hH_cg7?$#eCvDNS`waos|c3FIe9d<s?da@bc zl%oGrQMbCQ)u15^>ltK3o4&s5tinSTm4}zj|IxS44~N1EX*|YorB|L&hGI6N*^^o9 zjbAIUTxB#fn@B|(u066v4y1Pc`ER_52{Qx5BV(8ySqGb~ar2w1&qO0E-fi*14d>!} zSzY@F-|ds0A7PAVtwD5Qx4eS)-u{4*d#0Y7bklMF`Fvm4=WDn?g>@K-*GdZcmWW@g zBn5`N5x#JPvM?I3cyIK_2C`Sip#FuCXj?eF6|OdBv5ut05Z#s!PYga)Iil_CpDH0| z1Uo&LR{VaXfr1Q*^0?$OOCURMfG8Gh8<^m0Ij10gyEV4oaNXTt?YYO5Ol(Gf@Jc<V z+)&$LfAtTGsxEI*ldFnR&A8W#OC+i(Zk&zh<mP&wwRy9ZZHnPc7jg~ItK!%|gO9_v z=MuA6p9}ehvq`V({>zcYN6Ye=RNnk#T8smxGA3h?!C%)L<x1j9f+jDN4s-tX4~fDr zhv1o3cv>lHsXdF9j9K3tW^7CXrWl`%VpVP;4ZAu`xygIo9yzY&H1z^Ku}RRDoJhe# zrH=O9=J|l0Jt4YrI`k;j2dOo%dsgaJ*)=zaPX=f=H&&T{`x2Pbezx@I+_8JN$|kOY z)C3;#;t}AG76e2ZVl3e;4kD$;2B1y_lT$&XH4zX+Aea`oTcQs|#{Z|hKiJi7&ga>@ zT}ZDfC6Ieu&1(LmovhRBPV~G4dZsbFO=P<kdA*W^<+KtPL$((<Qm(o#KQ`6>IYXM+ zLeO>Jm0<Y8mb6%in~8HJTym!`bgNMoVDMXlo;o_<>1sWBo-%T~e?*fVOw}uhQ!=OQ zJgd)nF3D_{=Y7k_Zyfgu9O}-pUtStYERGEd2+%d0GV5GlCUMg!JUWT{9>bouRU;rG zlvGFQ%A`N9e{tAJCw9oj6!JK6*bKX1OYdZra1qvXG;flfx&A{pv{e_Eoq}EO*#oU+ zFw92FT0t!nGPF=z#Q_>0^kZO;JwOMT^8o>7LIKj&pQI9uB+I8xjjhZM{&^TZf3$xe zW%Q)~vU4?_S21UeT0Whdk(&BQ4BH#P>6r=r)_*bhPW1`@Uyh>;4I+<D!T7r#cr_%B zt<~i&WpTf0l6u*=F$WUukkEGJv#!W;OJkdQ>grMSN)&0$w8vQ8A@><}I+sXk#{G0K z7xsaXm;7=)Wx1u0OOOZPD8qsTfAv2)WpkfZ_mYWB+0bv5J!8kr(kTX^tpV(Jw=ojg z`%$!)Dfl7`yH1is`v*#885-hBBIloorO7<`uj!*xfY)TSG^{%WSBHw(V+i~n(S`yh zaNR+jKt3OaNZXVkc%S&qLlJ`K3M7#?!%^B88VH&ZLRy{e0Gt3e6b#D#_r`+|1oU>j z^Z;|p04&f!w?PmBDANB@JMd%&z#;Un8r+08IRE}Jc<agh{lh@d0vpr;AaViy_<7(i z!O%faJ-_B+1f1d{i8~-d_2j`0#c+XBWy@g|#hgF?NHX@eIWJ@)KITgNQQ3)_?cfc$ zrnZ~TIXH2SW^pnxT!8m|P2Em*{0>i~e$E&sbS;JJJUe~jwBplRQE`>;3b(ckNQ4JG zw$-2Vw|Ul~Zjh}V|28&Aey7>HudQ#UUcHTv^+7^$qE}|~j`PVX;x|(@5|fLG#L+|g z)15GxQ5@+-F{8*~XkImmb~rs>j~H0oA8ZD7>FIHLw_a=SDGTW1aLExz@zhTF{>vYp z52X?NT0L4ly`(>6`(W07yd79tUdk~Y=KLkUx|mzq8h=07QtiMF#Fy#!$E~}g+hf}s z+jMLsULjmJUM=#a8ySm=bbLV`@l%d!-ClZ)??hdhMzdEbFM5KnvkUR7am0xbJk54= z=7K|UE%5%QH<QJ}pMQegks$3Rb8bKkcxCA)A}k{hn<Yp)`@kEc_Uqx0#V!Vf0;fJ& zKD%PAmrFp?8s%HK>FR2Ja_LRO)b%xC$z{35Jd2Q-00v=Ku0xIl;jL8NOFBDhhm`Sg z=-q`qjyD&J^xYC36qYQZmU4A~kfC!<@zYy9zsfmR(iqu)<_oK9n`Eh#FTN*=MDZq0 zxMHdnduR*HmPtM9>dCr8q;8Lo{mNHkfqeOS<m)5t3l_PxR|f7632$}w@c~fz7W@y{ zP;#v!qtDyQeWG_M7(+jhwcddVoRm<LrQ`Zuw6`;7Lg}5@)qehCozfm7Pq?F*AZ$!7 zKao+<8W?yab;QNkS;2hZrN`%tSszcbRk|>w>ub)5Y3%}k5p8c|hOOAPXHHWkXcoLj zs5-b4^s!!ZX@=Zt%3M7u?1Urxxob=uzYY@;n^HD)NwRYAevYrjogqTTiQ9=8gNRSD z5>hrMDxPN_0VyV3)Tida)U=M<BVVLzWMq6<os}*<8ME{O1GSbFSeFJsG+sb|<n+&E zuJz>H8yvbpcx;=CTib+Nwb*~V)dTz0L73n$L@-K#Ar-uY{a+CXQVG8Sogn%ZTt|XF zG)&+CJ`Z9`;GPO%cyIy`%r*g(4H_dMGXXMApquP$35$#c-W_OEc8eh3Rc}V|x9l3+ zAiwMB0M-MAL%TMxVZksAOMV!@$km*m7<>mVZb4&R01LH%bgcCG&p^3GfM-aC5a{AV z4~?F2M~DFMRSX%aBwY5TGDi<fU)6h%Ysf9AuRM~ePf!kz?Fra-^7XESv**QXQYU*% z#CHz>WU>jk!SxVn#&)k_R#=7Ad+bQdNIdf`ikm3O{!z#&C|n=N$Y-7?@%+cA#AM;u zLclPC2j@A{07uT3PWEFv{8V$8(CO&9KMjA>mJZ+Te*abU(%YDn`>@DNa}z4*kqn`h zmNAnZ1n<<?km6G23ko+)lJ`=Rm564Kz&jw7``H?g{<lPg5a(Mpg{&HX-I+X!vWKTD zufCJhR;a(w5rP}@Hk@`TO>g;PBrHy|ggty_N-TWn1;d+y_#2>|P=wbQ_%eg93m~S& zW??l0qC&<t`5V)YMi0(zPYc)Fx7V?3ZlbR!zfDBRxa-f4?MairSlu2U9?7UW>!0-1 z+*N;~_wj9mm&a3)bk`TPNiIH7d9z*F)xG~c8oc`nKc<sOqIX#Hdg8DoM(E^RNBW6t zv00pl6h;Jvn<&rUNMU{`Tzc27b{{bof@kSg>j$>>hxB?|frEp}x?jj}MXki37~Xi+ ztUNu_;~8d%@b(?yjPU?4Q9fTQxT%qwY~^<9_O{gBFn}{j8~Ss+N9#}E;5tM804z3{ zjr!>Sg*AWc8dQZN1Y$8JxPnxC;O-f|F{}upS7t_bhi=`P{Y24Uh4R;yd8%ghM>xv^ z=H5u><lTGseP&D?7B0-*UaIxFH#_mr)2qo!DKNJ*xWv?OzG+hJ*+?)M{&pew<rip% zV^kD?tv#vANwa&?RITT{3sEHoq?}~Kn6<UF&b_F=y*KJib7$~%A^JaSb*mTis#Kgg zVCC+YU!6tsJxEN`tR*me??bPB7e4*I+B~Horl2DB<P>vcHIUI*ESpSl@J@g=BdE}^ zopD^zY&<m})L`7@rfS`|jWGDv6n*G>ec)8^9GupI!}&vKZq6tI)uhIGD<}<(;k#W0 zH1|H!eDbN=?WvPB<y%a<|EL^1+?{&=x<eNL7c7XKQN;c+{eZ=ZEXYoARyw)MskUiZ z3^OY6dq52Y?*V<@O7xw}k>#hy;p~neAAR3l-{Yf~5xt;f_yhWd-{S%Y9!9)z$htp6 z;d4=;kT>m5np6v2C-2<2Bxy}#(}`>BzL`#9T^_N^qN>4lv78EO(ouQ-KpgLD_DCg( zJ%?IonBMB}Y9YUoO`Oq#-3im3$D(GgMZ!O`=5R2a98KQWsNp*j@oO)Yl*|#252>8} z`mc@mdq;I?aB-a946YCacwKgZX+^+1E3*`A(r4TNw;5!(b)wu12EJj>pFTtYSS=G^ z%)282dGb`KM$SLA%(xED3bKO0Z<PW8%y<HuS;8l{VWmK68v$N{-+rP%1Z^)c)XenJ zGCG=%BL&{qiHAiRW(h)Ro22BRe+XIp=~RJ}j0{q}$j1k56oq$48{gTyJEB(RtWffe z4aVVhP5Rwf#x>3qg{f_ozW=ahoD=sRn&Cm3exo~G{AVgbdxs`HUb{@O=ERvgIU(Si z-LelmDrSTr-1atecUM*`P1ca!>_=R@oaFV!=H+r>R&Xbh$ZB=ont!r;^JYY4RO@Fe zqbpFb8W8(LfvL~@A)<%taUF9!Im3fLe>;H3Md?3m)Q{VSo_3R8y)IcPR5n{-3q@rK zJk2A{gLto5dy%_93SFMeTDfcb<<-J9JPS_ljk%tCau1kI<RGo5v^L(i2nn6*$G6A` zXrXXc^Zn%O>XSGtrsAR~ep3!f7KORGGx<b!{`2<ydub!3*tJch-nr_PEG{#PJ5J>V z%|7$=pq)gs_7$$b+eGR+WDxw%KfVeN;=|m1Tve0~i^bpA02mAbkL<dKMS9tIgM^l_ zj1R)>+vW2U+lkAY7>jzc$StK!wY6zgvvb3D>eb=4e!=+LfVk)<X*l@?d)gq4_jfMv zcxZ#!X>aQbwid{DHai~5HLWqMt9Cy0`5_~84DkR$0y~6-oWb|3w0%pYik`!pgWaMn z=C6N}aV!0Civ~YdlKboX-n)|4MzYuwaTV`NL@MmPl91NE_voMPW0!AuctcqIZOspp zXB~a^NC%7D(}Y-UTbVE|Ib`I5%{P?(xF?>&#t-eI*hH=|D8DjBmp2iA)c4hwIZ382 zRvw#UM>&<&mu+qD*%RBhr&H-{q{@yjE_>7vE%%4QRYYtzf7p3qhpKPdA)j3BZckU& zEm}GN2?O0JwBB%{<!<hed`l&cZtXttOebM<I@W2n9|&mpr4Sq;bLiQ`YWY+M{+BNQ zTL9Kw{DSQUmF(@gM+xbEzH+8D@v~nf6vI|;9+dj`u}r-1hFwh(r7M5NdTD6K3i<eW z2+QSW<X^Bghp9QBCaQi}$nW3FS(E21z#J39XJL4Qmt!hFOy-hkrZ~3i=)&s#`#QeX zw%!`jFg%yOWL))C085Dx9HO^?giL^zsk-^wMJW1P0|qEPVR$(I9}NN0c`z42LZ${# ztpK`A^UX|Y-(WUyP0<BD2*BPpg9;lM!Hfm$1jw<1#b|ef_9az;h#L;@p#Kr9MiW3> z20IEk-@|_dkytpH7YLl0gRr6z>`k8nrbS3hQA<=rL0y|P%f>T_{!k?=&D!gr23uep z^{C{@)eWR|(<C?w=c)0>tU1$X<b&%WG3UCAzR}%4VzZf|8RFyL^<E{Sy~GWMEPvvH zDRFg^UvOJ1_rKE6<yO*4L>P+IjSno1<1VAuYvtMRwmVRG59N<2ieLO$*Jwdqmqy>8 zljkq!VV6QeyI^`8ds^=Fj@SG)>(H!H+?$kk@L)vCgiE!tpck@iAZ3)6^EfcEKlptd z@4o=<7i-QFd3GZTW~PDUv_b=7X3qUGBC{xN{gEcO#;~sAOV*t^M=GC2S!Sac4)Xkm zYWN8xYMYN#*y(F7nLzjZUCD&0c?|&)jO1&Ix8eQ=S>aBlhGJMdBWTxrd>nSXzp#KL zQfJO`XVI*@irWjiSSkkN+t*CN;q0f;T<!vzpMhe0D_nw?wrEp@GcC^<A#nlgRo0>G zWR1(J0CM-t%lk;KM^6`_7>-#bM>X?~_9mrDpThe18+>ejUo!RGfmH8+>r<=pk4CsV za6RzzWbQ8vpE+WEl7S@gC8;aB3WbOL*SZRUXnj8yGpnmBU~{<#@U<L9LwH@ZO_Vz` zwpnXx_|-^Vd`3#*m!nyx=trw}_8tKF{NOeH6H3|@+x**SCkH}ITXjl)MzHrCv1{!; zAI+@VWCYk^qlr{-#>NXl)fA>*Ank(^7UU(&5P%(q-7r|3)7auy!^$lujtxS^>%9HG zd=f1RKQ%V7h~d|6|Em;5MdEmEe{<TqHSN<->_d3MQ00<+A#+)iFC$s<zT~qLYOT?U zmP?$}HqMkuaF04csIECbz<bOHN|Q<mgLO(4|Dz_S55swu1zBHwYJW(63L)c?92a<X z*GcQ#tfHfHmItqYJ1iX&v?+4Mkh+{RZ2fZ;J?CaPlSrW&pvL@hG+iF6qf&GDF1O{+ zOJ4che(bnuHGJ>ZM{6%3wY4v$pD5b+L<}jlq)b{dwdT*|qJHgknwCJbv*F}V28pV3 z0c_`ByaJm%Sogui8}i~CLE8x=U;%D8OyD2_{P5=J)&_q8RTL18u3LYOb&czCe-^s6 zqSlLZ)pt>N$|RBj-I_a%w$~%^)#CWXZe$_ro95~m(n>g$`KxgKryai0)bt>nm}8nr ztx>q|{h=+o{WzX#*2<CDwcA<j3zMVEwkYZunD^@5xte51zWe75cO{h@s<<>=9J3TR znIieUi?ou5XN5x>ItxCT^e)Y{|8#?@Q}jrcjB`}>RR)iV#<h9i<~^`&WZyQuG&DD# z6kHg`s><T?<e8tL!8wDUuiWq_<Ao;g3*+=3+4_?m>`{g*X*mElu4{O`k3Sp`TA|c* zdvEULg^LI)c-m^Kn9Z#Q;u!DNMpC<*p$DS{-6r^QAweg6H6hUO_X0`~S^}$*PUqRW zrgIa_&wzyb9VSjO3)2ca3PbLW0l6DU!I<-ytAHg169vd3l?!YMf;zMyq7U^;Ahx8z z(^No;5fOBbuDO7K!RQ#&F~bDVXjt09ZyYaRV_HmXPLqYLV2q##AcGJCD5s!q1&TNv zSYUTZN!e@!KPM8JMlzmn;!Q+$J#Nj!^$+%*?!K;^`@Mu;7Z(`S7;1Q7yI9S^KM8lQ zs}fYz19e;xS_weJ`&6`W_d3~(knHK9<VNgK_8T1-Jar{E(mh6=n?d5QGeQ&X-;`Ji zIqwh#B7BxqiCvg9BN1Viic4)a{PC)EcnO}dttF(pv@Q=UyK|r8ssGk;Qs#8Au_+sl z<vwP8&}2;D*K*_Xuo=m%n#{heGHNFKb>IE*v3qECFXn{*b-COxZXPT^LrJ4Pq7$3_ z-c&N8t+~Y{-0&gNd`#)>^GTjYHew1p&gYkW$&eE{sPMR^=~(9tWg}-5gr0*{YT~<~ zyGxHS^c)PYLQ^7?o?A_6<xZi#^xDwRrd0&6pJF)O^6SI!)`5&ti4^$?`E!?utsp|4 zJ}I{$OlZS>Zw>9<E-Pe>)mG8N7vJ5@_^QcCmgml9vD^JZ)S4BwEAkgNjPhc0)WgNj zKDP9jcy!y{-pE2J5NK3CLR|^}{PU1KD2ttejno|J`oZA?;uiTOKP%9H1>vRP1MO2+ zUDVDSBNU8e&M8RM(r=3HJgcbW@IW>EVWg5$27YZlxA=SB4ysddVrgh>N@$x#-fHka zHeWl$6fe}jI<FeICrA9I=jk0S_YdShpY?p1BPs@3jIGe-czX2l<G?QM#Z1v}MH)j5 zO%vUQOBzp<9N_Qc-+-l1LTEDTK?!Qsmif0y@o#HH<)TKWHrEi~xcqnPYKDhq-__ca z;=sTAYKhz`r;JdER1x^c&mn}75n4?TEXh{LM=C(mP(Mo`tpMr|0&kj&knA3PSyaMR zBQZR(n8#7e8|Aqj2~r6@TNO?!Ydb71$|K}jj(t|1=;D3XUaY>z`XlMp<Hzx~$<l<P z=SA8h>Cr(4$mg#~%VZ-`2kpIW(=a|&v&iaSX{44s>|g-DE*IY-X>*C<Sn-LyqSsm7 z(~)B$qLZKm5|waZ^$N6GppN|?G*)0N6OaTDFl7*p4}31Tz+l7xcD_VN1S&xO9!N`q zjj;d~i2%1YgvCzE0ZJY0*FYjU1if1k*kSypCDYOYP$9VW37!Q$a2o_imX5QLjFbXT zb%I&!n}$~<1N}C^mtH5g#SBb|5k*3<x+ASS;3m9@<IS0zmCEVnZvmYDI`J@MrDt(y zlo#F2{1s~+&|H>^0c@D%WDJ<lJrz76y;4Up+T&CRF5up+i_;?|xp5T#@ud{}LfnA< zssx&LNt53tIq}&ps8N<3jp6kK|H_f)&r*nUnRG|H$^yV>44?v|;?}!R{A>z7wlt_1 zv;IJ`Kswb=!(qtGdwYqW?_I@{#TR_{Ht8HE3;*l3t^Sj}L{wBBx4yS_{0|3sg)sQ6 zhYP*;rQ!=-Z0p?j{X>CePI37qed+Czl~a#8nPmYJZSDA#89ubY(J~MNclAdBHAyI} zrU}AofY+=K^W|woB8;xN9MMkM4aurc8HDZ!BO}~SPI4A^MU(lQgzs`J-kwHT;i9<e z=%scFa{(o<X3blb=W<Q)>#~N6;sLqZ4#_g9leG3f9L&<1TuPks`|7o<Y+Ju5iLDkl z9#^}s1J)oqZ{TlydrSVD6*cK11l)s510kFl6K{5;a(snmI(+Ap>7pK~(+#y0gRctd zXFgs3rn#P68d52kN`P7~kl)E!v1WZ6(WADspjNh!THQRXe5vU}eksou4FZlv8Y$Ee z=SH`TZEp_P8W;Fg;%*RmL>970HO^XV)r^G#$-nP?&oC@+bQ4w-kB6WyB0TUwcw|vK z$>g`vR#xyN{k`t0kpmkYLP+kZFS&`xm~ZT44asw#VEE;ForR)>q(ukZ(iZrv;Fi_! z?P(C%qOh)_S=G>pD0Km%rq-b+1Ec8}jcIZW&ebVk*GR{-rCfSycTdx8NJdY2$u+M% zr>^D{@;+#4&*$S-19(qb?RDz($n=cZpy-3IzsA_R|J8lsf-SOX_UFxefnV$k`T+Pi z=C+?c#%xKPa~VQi6K;yn?sk>G|3TBu+mJk(o^`4SJ2IOQq@jA*+$8$(iBtNlOnJ7% z=jvvM>b2{m+4~Yy;$wZ0ZFCvui1NDWjqxC^KOh+D!RS3k0$xjG_y?eLhD`g?O<X7_ z&SJhmt*TOJ7Nr^FjP{il^pb@9It|V9Ceb`jm2)@Ymu9Gp@GNc=p7$gE7NM_i&ZT63 z&U<mE1=t<6qUIw03J?&u=9~?9!<w9qEbe!TpCPBnx^iy9BeaD9XASJ?CS08zcN)WW z3s`QT7>xJDafdOiY7}qNS%s41IhSksk6d1QMVDgfb|LK2V1pb^K8k~^h0H01!cK_` zc~}~n*vXCzxYAaUOyE8$q#r{s@0LF|xE>A%?fR)xVARpDo8;Br!SjFqyvZCx0%KK^ z_jmzW0J9EGTC)L7$2mR6{f(IT*EUbD$rBfRg)`v{UW%GrY>Zwo)n5@6awZQz{P-Hk zq+({=$pm=F!{>w09%BVvF--vlPADNBWUvz_#b|W{h-vsJ9aR9%ln`7+NP#_-{`z^t z76B?3e(G)?`U9{(AmC6yiU0<@Xbn^^;f^=s=BjKqu{j(j8V}2}%GwAbI#!<_A|ixf zCVEuNOe*0bD5Ga@9UnNT^x9<lwdUZRy}6$M%zsoh{~5<0-@WzD4uqmOl&|AYDAqz^ z9x>pI)I+Ka-m16&xKHA2leXqs{2cw}3r_-pzu3uJBjZ_&)7kI7)+u`B<CpBLnW<U) zj62u!eq2s^Vj?V}sQ9_0fQp`*+TZ)^?{kw{+$IcH8oRoD-T|t!(-y+{Cl~thy(yPb z#rZb8c}afK{VR9!^+W0X*pp}WY;}gQU?_92Wn*_m%-@#{ITj@9t)R;l`@gnXM!h>; zQE;ea{z!jz-mCLug3*Hy@k&w>TWZ8WV<FPf=A+@@k2H|b&Ac|YH<$KYvXWM8xI7Xy zGUAfN9;~(|PHr%qshmIj>hZ-$AOUKWG~FrR)2t2^R?plFs4Ee)wY5hQe7-%B2rKg6 zQ+y%+g5R4n(!VPG`U2=zOJ6dIucEyfPb)jC86Mb4S$w->XDMs&3)<q&EN4?SJ&m{$ zV{r5M)A|z<u4(q}2dswPrKhLfw;*@4Z5p{dJ%ygQR9`!OBgmg_22CXBE>ZkI-rB#K z-S^YIloGV2O#E4Clr42<>@h+J99dT7;f?fHGB$tp{B*Csv)5tH>+&UwBpKD~23u#= zqJFyD{MXYN0)OO;jz1r%>96jdE0+Dx^!0`Qh3*p&5VcB8Rri_i^Qp>&3(8!|=DD!h zd7H2sw;w7roH$;3ef9mxXYEYO*U3M<X1!+F#Mo|4UI*ItOy-Zf1W&JFjO!?-!=t0& zz(fk~C#~#-OkJJL!HGQLOiCx^zBMJU|4NTB!M6=`!dhY1gdZwhJfC2kAk_p_Zy=%# z<-4`ECI2wdnfc*kYtiDUfwl7zPuFWEkjAwQZ{97vrrGyq@C37jvT}yR+yr)qY@nKG ztsJiqOTW{74pMY0rL8U>z!7KCzw>P&Yc#7eaAt7m#kb3KCFeK8Av`?&#`O(4U`)|L zNZZGCGe;sCtI%y8ujHC$mu{Bm>x%{QOL6UkGz~N7$v3Ne;$KrM8bgy)JsFO%@e7tf zd+am=b+9a%5Cqar&=My=Zwa!#bj#1abgDAMi|K+A+3!<0p&T~x;-C?oekjw~4l4}U z3EoCUZ%T+??{ubX7D+?`@E?Fh&CYOPlcBu}hTS8HaHI+p5=j85F{HBv9%CaN!F2YR zAZ#o|kO)IWTyVcnXE^|P4A0A>eECWCCjGJ)Wo@F|W&lE$42Pe9aWwapCaaag<}pH> z`&-&lg67Z2>N@co)JAYrY)V5hw}oO*<TylHtj+Z+r~MOC$*vFXnqG@RO^YI)Zs+`r zqTHEm?=R?B7{U74*}Pv}y0yAZesw2_Z%g7W^@mPTncw1uuif?BASNQb!5oGnI~2`i z5|l0*mjI*XL43S)YJ2z1Qet6PZi|+sMz;>3n{YBHG%qWl{*J!=HsOd`cwcdaa&nO` zR1RPaDEI;hn<YS)CmwQ(@PC7Lxh{HSw(Agzj>1T?NkK(D^29yXfGwWpoykF>x8LLT zVV3t;^SK!8kUW-(tfsXt_%wEgb~f{QR9wFUspZg(oP`AMmyeP)M&|$Y?1EpktnhS_ z%@d*4rUUSe4DMs-Qf^6TKr#;)=o&{$G<0Ta#)IJrv+nr0dKuvAu7)f})UP+Algg-H z1}GNzE?rSHE@g2a<reN2WOKXZ4Y+F|;mCrMG@H1x)ZS$Vbn*~ZpOm(3d&XOn_jB`} zQQgm$`VY{;isb&xGCHA{zw|@T2p+{_*75;!Uq}_RkF+H#Xm5{#s|a#ug0BJ+wpt16 zDFcvdAwX)zOh;fVghQtgoHmUVj%aJpS##C~<8~w(6*o2Kp-t+_(_ec};yVU#XBpK^ zhe%g+3rYM*^imRvTgwO}+aYt`yLEhccPU0o0a@c50T_1~X`ASG*$OFp`W*uj-tYT( zKs?&`Lyx<%Py#{^?qkR|VrO!?JA7(_y(T}Imk#YTx*>6vHemDGEhhtL8?dBSG=*1k zK8DA$&I(<YmJDvz#h*P5`6<EVgDe^$AsS%>-EwDSO%uoi0kID2J$MxTuEf&ziU<!v zEFQl906B$kb<i#$F)e5>tXi{T3%L(5oXFed>`PSoE<FDbWnGfQ&A_bh(aeZqqqzIB zm}Mjmtu!<urDUIUwuyRn@<HjZHD?M@f9dMxuHFj#bM!U?doa0jhQzPLuUL?NIgqF! zI8G&Lu9-iLk?-G8O2IMuv9kf8&2juw2aK~#qTi`{X(*nJOgf)ume8@VU+V&-N<Svw zOeHwvfT*k|;v|kWjIFF>n})$zO+@EMJ7}Yqe-!m**Rzl87xK)R*16#=5ifYItYD*{ zCbLSP8>vnSrA1Z2-CXXH67WKSV<33<hx(q7z?Tf`C0Iqm6<_O2c8*t(0tw=2$R#8I zoSsb3aDWnVJivQ|B2~m`M#4f9%;$h4fqK3jh*$stB={P`f5E%UMgbF+47@_J;1l8l z6PW?H-#A12PeKmB^zf6w5c2!#0ugypQ4s{R3*zHd#8u3U0ke=0sHg(EV5mp9AJGPs zJqWBbV>DcH&4zF7@p1Kkr~=CfX=yP;-QUZWG0el$8RqY{*q~|kr0|~=1%1$gRK=~> z@qQv9npZK2U6l%tSCvAD#y_t;zd0P1CQag?))`0!LgDi9)V|Fxj(HZXM`{Ahfc*mX z@SP*2(>?n>X(cKS4?O8_F6S8raLa({>)UuK&(W1$^k<*;4CO{&dxz9brjjA+0CIS) zTWV>cK^MH(_YdE3bdXoPs?)LhDQJ2?uxE#N>4WBCBY_LirTA_;#&S(|OvVC<-<nID z-URT{%=@~Ry!r#Mc9q*+gmf&xnUC`y5<lNh37{#Mo4kuu+Hu0%L>x-0@Rf-Wd|M_T zr4_q4eDlc<N?%qU<z8@N9(Ovfx$s9WGrFC^YDB};&FhsB0%XDCvbksM(G@IdY`UNI zHO+~kOoTx57KGk{<*^o(?o`4;L-ckv9m0iEvD!$hhfs2v)!fhjg5u4oamIm4)X)DZ zkDKr3tsKHHrBHZ@#AUZp+IBpr8K0M~@2=Z#*ohA9g)Cnu@4wP!!pQtx_dUx03@_c# zyU?0$|7^0SD~l6OO`klqFWd5-_v9ubJ4#R(Vdvr}t${tC#o2^sHV7VqAtelcRVB6h zEz{B}UKL_d@G*fu7>q4^HFSD*o^9|k+_w$InZvui7z~xpKHMJxIquL9*KldjWTn9` z5(0#HuZ7B?UVDq6q5Oa<U{Ss?kL-WG!Ozy)Gk4+cDYi_Ku$bH<6o>7wv0XHNYnYIk zv9OA|QW(%tu9nJP?9~{0i(yAoHdYj*wX>K$kLa$%bv^#FHSdVdsW@-F3|}7*f;s!U z(!Qn@xTMeD(BY2&Aw`qbk%cj%Ft8NUB@NWFH+oqEwLcB1sG^PlUiMQ^%OPG}6oc71 zG#1Qc>O_&B;4ZpwH%GfT{Pu%~58*{5Ud7XE;U1csjT+-phznHlfRX<mqUN^{u^6hB zd6<umELWr7aWc8d$B(lB?bGeViA`&EuBf!mY5IGb8(h+8t^w(5$2OG&5o5)NM*r4` z)SdY2iE$IcIT3J@s@Q%&pdYFlX~xw{a(^w3f4E-)14T-wY}%!7g)mK@;n_QmU7PoD z3ix#*Wr6Ax*lE4~$ia!9=oiF|;|~FrVe0_A2gAh(;@Zp@m^KKmX#~&*es3OB6cuT3 z0{Gt#f+a`rg8=jJ6<C>4;Sv@>z-3Q>&`}E97NTda!!~08LZfM|4cainXlZI9#A?7* zt|hls@L1Jw(19>B+>BxD0RN&Te9_>x1b3A-LM>231h<x!vgLG$XqJO{yMZq7yII0L zhiM1HMK(+fI|ak-hgx?k+}v~CLT~<`)!?AOGWI**oli9E>Y&e1%hy=mXy#x0d+nbI z-X4qM$^g6n>nNT#M*@f(GcRk+h1%xU+RGy2$2?S>R(GO(LjInP!TJ09^IJOC^HJ+* z0U@pZ;8{0VZ0RhUB!v7lk4z_iDdl&_v!+ONID!1^4;)0VCtDL~tVErXuVu~%2cx@s z4%Iub{X)XPr&5`{S#pXLvNVRYu7Aqr)^u_gmnTM*ohFKMt$iZS__YL&xF45F*c{H) z!!v()QoClO94m{fg`8boj0B{nm!P<7hlHR!c(5Yd{biv1=>s1&Aw@7+!D^_eMzlsz zQ6)UgR;~0%It7`sNt1qEGPTpa-_h3N-u(1P9%;z6vY^yAx8al1F}LY=7vBj>M{8)o zz46T!FL7gO#fu8+-6ai3K`okN&F|>sGy&z&ba6DWUHnMMkZ%BY1f^e{IZ(!&)~-Qw z>brU4)_lLYwjvDcbzERueZeLVaH!U&W$N*fC>kBbg}cX5DxVNzPZ=vgua)8!C5gbu zqZ&|n_X_o}!#Y26@pR2aT%E6E$e<|^?AqTZPU||-KWH*Pq2Wz}4aG`eAw86hIj9($ zkEOsh*#+Q8i}ZoPugN+xVnRAH{O^#rfk`viVj$i;JqQ_`ASdWVLcmf)!1DBHO*Ztu zPUn=5FLAJ#r9UtszkaOs3@tYL)7xW_e)@}TeM2WIs22VS(#8q@nna2mj8vJ$><=K{ z^LR!HT!1E9Sn*5%e#V-An#*ZR-7X!z&-mBH9-D*UrbdLnedD4ZLdk{~A$vt}vl>Yb zhq`UkoHw*{z`GEZ9%g>}k~utpqaWKCCnzi^m828d&G?MoaXr%DA;X_diH{yjfh@T| zD_NuobdB(B%!E)LB>LfhIxS?Jfk@KXq8}y!x=2w7F+(0nAVSkXM5;&`y`RdN3s@{? z5Lat?76z<oB<93%%WiEy5|%yf;6$5}KRI_OW#ry{e%I))B1w{td1QkdX>BGB6Sb+I zxUT$+>QlwmBlfOJ;@ZZ&%8wt~x4$oM>OaBuWh@srD`}NE#A9JNPwfJkreRcrN{83i z{DU15-afu^#EwL7#uqj=N$95k-4KBxCO1xJaYk%`&7vRVvqgDuS~H8Ybxl&Yu-wIv z+Qlq|v;_PCZig6dPl{K9#t47$8F|sgmEJ&e4YSN~uy`1D6_vIsdY_S!#a=}%Z%461 zh6Y%V86j-qmRlwY76Jw5Q>aus=x;Ksx(P>&t1uhzc>XEq)o(mg6zGc1O$@3)gi%2V z^6fJGV`(#BM+S%XZ+$k$!be#s4306dY!Ij`P-HNpWS$j{2WcAoGVpTev_mE=QUb=I zK&YKAhfTDoUaSULJoPIf)>j-7Hqy>Yky_628P@<rTID&@vzBcUC8k5b|JZ~Jx``v{ z;#bec#;{xEnfWBnY!)ZuBKc+RS=YYJ(FiGLo3l4g!`)d(*+pegVZ%9LWjOyt8c}(m zAAbRl4eO9)?Oz?wD&<5;{ctUm@+ahp%dYYXgS`3M*8BwupL{$0ThoKR`BF!u&xO4e z6FTTa8jeBDS0Js1X-`9DV~TfI4Z~e2koov!PEt>ogF}oRez2LdzCAOc*~2f#MDGeD zbV$>y9#(JPt3JMX(O417Y$ncV@@moOQy~`#1VH5L;#pr(@F|*r_70toLH!7hj;QbL zrk-K|D&%cUK&HO~zL8<@6YxbDEUOdVvBZO3m(&S=oqC}Zj(8fh%i)S#msPs$G?<~u zPi%;DTMRkblttG&C(<=42-VE1XzoZMZ*yEwbhCb2hfMfN5t`;oVrk>0p*YLlW;k6; zf>iY{7tPg|4)(1zpEqoHe_nj>ZMs5)xT{fJLUAvXQ^=csU&z~*m7JPnSbTEdWY6j# z=6;MVS$WT|wLl8CaNWL;^9IfOPDXP7EP0GD(z&xa>M&X1EMaf1J95QblYgDMR6t#F zrEt%T+{<<Uc#+vnS+7T}XOL*2<Vg`%$HP6H=X0NQ5q1Kd>R7}X^{ua@6dH=F8<hQK zbv!Oy8HXAoaefniN|MJrDoI?^<S&XBu64z6AH;=*JhltTmgRFPJcm4wQ404hd31I= zaq$ghN}}*&k%8qx9G?|USy3k4r>*IE<Pzkb!4@w4#D%bv_k4=mJj|T0_~3YU{4ro$ z&z2f+`{J;aQfy2=mYKYJb2uD5r5^7Q0=x}s;-9p_a_%#Wwh&AP3k*W3AxHKRd-JLr zKK{z|mjzZkZia!U$9=ng8u`@M<Jh1T(p;`Fq-yXGe~rp@`zNVy5yhUvv1EDkErpC@ zl9+lHI7n#t<r(X@D<zhx8QsrL0|cqY`Ig8Z$DCg&JlP?wE?6DwI73w9X)QszPR!NB z<g@}}-je*KX9nM+$Ai)3NFpRBWRYEepJX&NW82`*P>QFSif0!m1(J1fu_$&T{_Da* zTTyRgDYr(GKRB7W2F<jAEg@_?E5JI4WlQb4-m2oFzW0*(PBE#JtJ0D2=I<4x2Eu$3 zQ?nat$A5+3rWqZhm7KCpc4jC085$zKA&qvyw5ar<bX|@bo{@xM*HUhlD0p8XLa<}v zj34n4xWUNysZAs{<1W2q?>xTFBb04n@T&<f64O(*G6)a{w?HGb1vIY$n7axYAs{6A zr`CW~Hlab#2!XW<97X=WHXht`V6O=iPElA^!l4NG?qK+Oj_@%W?mRc~@EE+U6h9XT z)*<9kJOKSH3umKuL$GHFB!YSf?%(h`K_LRhFtDfr2cxKv0t9y<5!&VtOM2K;*MQd+ zWEcX)po)qR5cuVuNUr_e-LtTlBJ}8X89g&bFtoR^^lkgn5SkOm2@43Mpw{0MvWBRr z+rKJG1uNsykfk6r18cqBs@73ZzIJAGRwLY@Ko9EAtO5C;ItspS26qNU4$Mx$otOPR zng5=}F3Ag_2KIPYv+DhbqibroaRwg@R?{?7gI~bRkIlT(jD@2JWRtj6)Lo9%vrUuz znffmCyM~51^kxdS%<2a*84(>XAV`Gzc+=k)PNv~k8T|2X!)Zq}Pj!D+=Qmz06f8LX zBx)t@kH08$3!`J}(@Nbp-ZXjnkob1ir0E|`14E08yh0w2f~ybUzD`LQrTS7<d!q9_ zy*4XKr2xWGT(G%%DCo$G{O_qqfV6vSBp_s+5v{`ULhzk20(~asp+(f<G^9~A{<GH$ z;EfH<bqu(9?Ur#4@!F2v=P#@nxg*@xS<LKC&(L2_BExFVDLgUm(yMOt4y}g}b~kTP zoeHpJR(9699~5u7Ne)!@Kqoud0%%X={XyAwq0vzY(i$6IIb;x+Z5PxMg<7}Qiz;#< zpKJ3d)(sg+;jd<~%H`RBlK77iNFV$d5~UmT0s{s!{4aQ`sz)(G4C(cwy!F2MP994= zi`k2^Tslo%Igo4Rcft04cIa40)hq^<0{s8tc&rP$l=aiprGL7$u(hT9E;Mg;QrAx( zs>DmDjB=hwJ`|jF_RA>TPK81fjMTvqEdXU45%}fGvLG7@TS$Er6xAUw<N~CC+L<H! zbJ$1>@xX%TKiede`!h}^xBRJk!Wa4DpreS4(6;A@1oMW6F>K7Lm3(Coi`B_~%fNv{ z@S+A_k4CuVXvT&B)WYK8kD}7xYP+rC2Vbw0>^OV=E2!%ugw{V6u8+%eUZMF*l319$ zRHqD${*+9~lV2aCuz}E=dM%&Aj72Z}0MeiK&Wq+bs%Imgs_a*I4ey)!v{F2SS~+J` z-I_+KFn$>?B`iRVZkRqsPj7<)79dXqC{sb7O0fGx06M^D!vJ7bB2}~y!oSy`?ORl} z6tu?Rb?`OXXCGN-Uj7JGzm(CX$-M5EZ`*4BIvWa~BpwWhTEO){UCAlre$IV{vCQW- zX!2=xp{sFceTZao74M^#9szD%f$9kI%htWLNz!_hWW|&sh9jzpR_e$?F@`Yw!T#aU z5mRDkTJ^vgcx$Yz>|DS#>T=h$GjGi`UC^xpDcpm%{h^JZUu;FKdE%GVsBCo#hbhlJ zqI)gGr#cfykK>IeqGpi0n{|UT>`+A|G-VVQK5Z^&7VtCfQ`u{U{=e3nv@VcfkI3GM z=0~*p&!DLb=!Nf+l{($3mp_`2R!!sPymf<4ow7&KJWKiWnp_&1GfuJn)g0PZS+$y0 zwKwIgn6e6x>=UFQoDR)m!6!sea+848b!G&lHflr#0rm1M1Vq$;SEtn^*RVxZ3fP^$ zx%ar=FJix)ykK&LJKm=Mh21ww$sy=I2{6xxHkUA<DB$Dv`$h^sD<ygc-UH!2_j`p6 z_<I--f;E>A<Odq~EsBv(gZzY*5xL5zl_GC?LatH>zPoAhN-FPEg=v<04lxWoxu5&3 zkZWj_`P|eO16^AFuTI_%>UB4rH(e>_Tg;RHP#5zF7dd#*Bvx4Z!=*DX0WB4-b>QN^ zMw?x>#3$WH&EeMRs2?R1hIZ4`a~)lSJlkZ-dMt_Aj^=K;umS5fY8t!e$B)aG&L59Q zh?|AIZ5tjP4K0zaoHEVAIW)L$IoaOVlvX|6deV2pfcgrY)4EWQ1xh09IOq(7+2A0v z2Y|9POATWE=+MNr=T`NxL#OZFy`ppfi?)38tSp`-i96Z7{n@|od{(C#&Mneo(d-E7 zN=4xkbdRNSRi5wu!{pV$3M(-cEoT8vPa{%D3P`a#zqL8|8Pa!Vt>EOjX6Rqc7Mv?_ z2#uSt<JENHx^s`Pwp}TRB4O*azuohA*G0?M59vo6juTRX+cai(9Fs%19?_QDjfjXf zx^($e@BSOQFNh{37ux<hr5<x&D&Cb)|9p^h2JB8Kem%v--|6!OX`v>C-NsLB9{;=J zlS-PU@+V*7tTu(;7t+D&)#MllxT~?QIv(!oeKoK5u6x|;cIZ(`I(lg2P|2xc6K5k~ zvO=DMVtb_+5Qs!o;Gl#Fo^2imye0SYLb|z|Hi_qrXE_W+S(sngJ^{7*d$1G1O?5Ro zwx80eAgxc5unY=6@AJ{t-fwxzJGg62AN!`BAJ2RLz>IwVz*rRO=c6=mR1qAg?mBU2 z_s;L*4M=jIFf>PKe-|Elu5({ZN<ke^)t{=10t-v=5kSeO9!cBMVg^?>mnpwa%(DHf zVB00-AN9%_I)@{#{dvI(e%S=dngp7ehg<6BO=B|OX1K;{w8{ezfJ4LZUu?~I=O~S& z$4)8as?Wt6%ZNRdy7I(a=d$|7$5QHM0KZgmK}0|f{d()gC+1SBN|807axwGlWb=@y zscOnfHR`*c^s~ua+)6WUt;C6@N?|WJrHIgp7{)0y9g7N}R?C(YnWYV{;+eA6tUMH6 zDS4LxJ;*^Lrs3lsk>(l?TO(E8{@d~H#V_I<%=?6dKRsXBP684lUk(44Us=n@eBIz1 zDti&l4FAGPm{Zgq9DQ53w?MbRU~M;*?r!96&gv%N&+R8~KDW@;RC%BOOFW>esnwuP zN9M7|(I((R1D6$sw3$&VH3D`}W=t%k0#Cvr2c9B=J}>A*Wqx1zGtE#8YX?Ro1Wo9N z69k=?Ln;8j7Jx1QlTiz4Rk;0v@3dG#%*X%X?^8^|C&815Y*eBVEgP#M_|?E~1C|Cj zB^3qXL<H>UiId`jdpW?%I$L$X`fg-%5MgFbqE4_lSR_|;ZO~s9gQ{d~*5n_P{v+Ec zStenW7K`R-8q&^?c!!9qlZMlD)J#s)$8B+cGe%D8;ieBkwhq0zQ(k-r?PS*aD0m+r zX%q!rPU_NgWPkds$34cgO8vdp*gs9N^&Z%zqJ>y|V4W?AQHjsYw`DUNSsy!j9c|$@ z@jdqp^+WRjr7zF>CFwVLcdhFcLlOly|I}5(dp76q^f*_u{t@I)u%-P&14C7}It}C* z>gX-63ZA8`<xDlc#9-&usu`QA=H}cFtap7sy)7!hU~(Q=HK-=F>q7U>y=+$pc}O-a zd&<+dNnd*M;+)LHF-2DdJicIr@dq3LGh-Td!dC?loAkXZLQROKu)_`hpERI77C2Px z;m-%ypB3VPe+awZDS-R2uwC6%>to-Bg?F*-z+;p%k}+wBe7&#BKIy9u0^G)tBB!vy zY&MbQO5vR${s_QLl{(QGe0NumxvuJ&+&3fM`)Q9gxsd^S#G@h0`2nGw4DPvP76G$X zas0ZM_zim-69lkHG~c`Sa|SV-aY_CPwQ5GMx;6q+#XE%JN1&D_NsEv?w8POEyx`G* zl*Lp1O>Y7Mb9Ds@&|;Zae~f92{`|{u(RFn05RqqU$fuK5k;EBU^3Mpp#jEKj>BqBH zoeI}&B>%B57IN5ZRwqEs$VUi1C&zw&7+VCR#^2?Hus~=#oD_rQ!(pvXmHp>!fK?++ zTPH6r^RUeX!q&==O{F6N6pL$kTNs&}{Goi^=gyJbS7&#)*zeh(_~LQ>)Q45Nhdxc6 z${fwQq#Nfs8ke$miF^_}VPVLucA~k-3!n39-y_+dXD0nQ_NXUW%qE@mrL;0&JqW$B z5502SAv>>r`PQ%jT9zIVn4-&Wi^GK=uEcf+pZsD`X{%F{Y9p8XJXYns8(W}N9j_a0 ztsXs8-DY91V|#*%(S#5j^NZ!QU^^QoNO1|$U4UoBiGtJ>Ac`QlgKRhSI?jj*4LG}Q zy^`>K5<^Oys-;cpJ$UnGwf0W%in8A`xCzyt@YSe*H}e@BusV3M9lO*BQE#Sh&33`L z8;e@^MFFS{A@}HZ`sWgn4GEP6mGnjS=c0k14yWo8-z?5^1|gyy!f&CdD^GL31hh=n z7R?o~KXh`(QgF1i?$M!iEY%LrA!C<hL72rEF647CSwvdJn>SNDN5;j8ouezUa4k|= z8k(j<Z%_9~a%;e)$>6?yeJr-zN&VZQ>b^XDw`}OG{<Ei|JWu`eHv~*l@Jt4-G3CM^ z*S(U>?e>G>gFPULPhkYk*>xtTs;e8TKJYjyhCm9zuoo2d0xk^1-2wKz-$*~PEUSIX zb@~JGHh(Q3)T4k10>Kce&U(S17%w7VKyyrC%46cZ-)I62uu3F!R?}p^3Es%ywg$zS zBRVoKXWWqB?$#0mRQ;8vu*kzkf#vr8W#0;J-Hk*J=x-9L)A_U~d6b;^N3`xti712p z0CJ?Lkh**ldyZ7tnCxC0%t|ux{`*Ni*QT|S*q#RH65dob<J!fi_KseDieXZ&X*qAO zg<TKoEjGhcR;20r@#Bx4@A=rDSRYm-7S6TNTpL64pIO63i9bXyrKHd`e0^ru3C9d# z?KST$j&7<Rj=>LCRx^RSVi$MDWpC5VCnAwMWE5PCg26XYB+nhBynI&Y`=e{T-ig=f z^sCX&jEvY7hMsiWpWQAYzqjnr)9sFY`@)r*;;&?k!?ZKvyH_@Au6{!CziS4)iCa%# zXWq&6K-&8>%qC_hHH48Hetnfa(jM1I;kBa~P2SJka(taf&gK98tlTalH(SWZK~Ae_ zK-6Mucf*~qIxk0MCF3j71WO{7T-{g5o2BsTG<i;>^6wR~6mBnt|FMu0-pMWt$hucT ztxWSfMf=iBd6n-vs(0DJkdvb=9R6^pdc%enNfHWA5mzp>N9DDMZrQQjNMu(+jk^t5 zpU8cLVLi#>31PSial!Emx6_|WofR5DJX+PVY!x4jiaIDIEiG*1voh6BnzA)qMar*c zz{w8e^^SHXC6;NCPV^G=!XebG0ckn}$7AD`bs<7`PF+Z}Cbc}|)`>-@Z#qGk0J#Ej zai4B`3*^hy)jZTH*NJan=r({VY}6U~n114wO-|W*KwRad^T~Oi6-gqmCjd8ST1{>a zr7hQ;ZFhHjv#IC6rh?jWo*s$qFnWK+k;J8w+B?M8BtIWd*U%21Zv4pR#D#P+Sn--F z2UfAEnEM@`Sh@4yX}F>zqgXEH>gr(<+QlYLp;0_f(h8mQW>BfZs=2g9Joolu28tWM zshS3Z?KsYSVXWz)^XaY$vmjnRlRw2Kjzyqnl!+^xZojz32L=5fD=0Vqxw7xq(o#NU zJfENoo*@2~XS+>JQ#IZy9ab^=<NKrM;)#~A?-bO*$Kn$yjZlP=n3l7}v76tTf*1Un zg7ambC?Jh()P?H?nC6=7cZ`t2QZ9^oh1yGxEzF|?a^c4P!SqAb^U7Lkgk31EMAq^U zl{=dk<KaqtHE4<Sf9-D3XR&Wz6)ml5u|#bKwcbsd`dN1OsIh+9TGYM$`_&t2YrR4s zKOP?$FS3~idWBDRfr)mY5x@@ze(LnGRkN0QZRG7W`{vA%#r>7E3VBwSBzT`jwVv9# zpKEAIL>gAbJLHCzUBAb3(arecOFm~TjG)Pzf_Db=ghB9#-1_-Bq{bn-A|g=q!As3X zU<b)UgV_kKX{fKwD1za~PniC|Y@o^+?i3&c(pLk)p@7~6qZg2gs+bY-z*P+7c^LK3 zssyq<L1NZSUpFF95IwV)I0g)`E$~|)K!frmUKR1><RQ%R5zN{jg-dck-1V;RimC3% zt4exnV}4Mn0hH%ORE~KZ_GbWpz0h#7Pp_g|%`XU)caIsMC=6<hx}CZJ$k*vy(u_ZT zMGZd_0Oo-#+82*6I+?h(L!@tj+Ycd*Affwp+hn#<Hz@D_@$@!uQP%1H|2+?mGYUD3 z2}A7a431dG2L{;2wPtmg(uRDfZTGCY8V-Vb+J?$y+n63;ScW489LJ#}uo!NSo;~dv zYLRRh10m@Ov0Ga~Sng6mol=)(%ShDU`?~G_Kd-ZGTLQy<f4|qm=kvKf*L!!)Y+ro$ zf7d(_O|D5j`NC@>&&>V7l>5i=$g6GmuzABz{;TDA-))PIym>2|?e3oO=sVkw4T$9C z(wFBaCuXu{sPdB^zj*JQ_~6dYi^CmnilKPHft+V|-d+Cf_i4qq|8-XV5BqypmVfZz zdmV4SaIEj%V}CBx`)^3EWqm!u{d$c@D>l!liROv5e%ri*t$TWaVKjXuNA?``;_u4v zvxz;>8{ax~{EH`-eS9~IiJC(@ew+V~=VpI-*Y2`Ec=veyLuFsw^5U_NZk+STsWtBz zA9rZH7*Be4KlYagU%d4Ei{o$YF0FpnqUqg>P$vquz3N9_EGhpc-Z}9|`9F4F`M<nZ zQ!;6?=X~{x7ytFv`H8Pzybx)=<E6e;J6}NTbKB<l&t4qII_}TE{!P`jTE|;uf4k-W zZ~r;tQ55NuZ=YZGYQsHU8(;fy!Lol%U3R{?{O>7O{_lLtVDCSkZ+Nt63DLFul~*4A zV_op&T@m}=<IB%Ing7|L8Q;FPf8v7!9|kwC`%}sz&#Zg6^Of=^-+Q!b=kVTV;WR@r zF=(*r3=26EK5SzWt*!HDtmBzUEZ$1hS;J=LCF97W>^sgLI{s?;;Hx5^^Lbb#1sD7E z3!RVu?myFu9v?5ful@4(KRml=^T<DD?7jA`F0UsX+6ky|e)5}jY*@JR*__K~XWoD8 ztCpUci8WNjnU{0VPky^Q_;KRt^P~6v*RjjZo$tRs`&TnVj!1PR(frmcW&haO@%hG% zukW}#GH3Eq{r$tkADsE{rc1wT-aLNxL$-H(UAOtETm5r!&3N=}Q2wr8Joadb=5Keg zv%wVk)wz-U=Dja|{cYx@uJaSmA35m1%?SRot)!~w5=WsBZ)|l51NbI2KUJAVX$!h^ zQS_az%=F5m`>`WZCL=jFpC2!~zx-6<fjz%ibU!<i<AxW%S)Z3=zbEVS&Wj6{fBoX+ zukY#n7V7`#{L_c7`_I7Hr)IQ&cJ|E2?`*#K@3RvJcU7BD_<m<x;r`OTr1P(zANz7u z=Qq#X8~*$IIV^p?ZQ17s%0Ib7-JIRF{dCO_KF8ZN<&mDLud#Oa<HGy14S`M;EPOMg zY_g{F{QR=d2d;cOKDKyY+RrvFIrjdkj`+r7Z#KX7^{UKmvr6MjN?$%Rv1eo1#F8st zoM*c1N35`{ezNe5&F632Ji+$L8(m}bieoscPu_^?`jzXyKXm)%ln*9*cb=w+A7}La z_#59l^V_Z4Zff^NduFxeo-mlw?5q_-L?eS&cy2`WIRE&xt%nvdDmWh)PUdM!*N(Jv zMgWhCoYrvZHNx>RC&*9|EV(pd>PA*33)L-yd_95~aATpxWuY>zS*$RO;Wbc1SCxqS z$CBX=#o%GJvMo;xVUtY}fvEBFV*b;scsJRd#tjx_^uP1JuwU5J`CdczA6|UqZ;O`P zKFtnY8gk^ZA)A4s{`_aoZ+rU(_q{jN`}A0urE@ZI&XpBs#{YT#+uxsYm!FyV^{@Q5 z&AR!(TKCt_ZD#xQc;biWaM1dwvvjg)dGOEUD}HtMZ@q!!r+$8WIQcRBULG5N`mKh+ z&9gszbX0G)>sVIM(Kq+LA3k)Zeeth;F#D15jrTdDI2HstyH~ltJuiBwzvJihM){?I zfe#-lxaoTzfAObZzTW>{$H|+IeR!bk@5A{IJ^Xn?+4;=#cdxm7<NnW1ZFyId^kZeA zNkeygtmpHNcTb(a`?`x8mb!mfI`GQF&jeH2s=`T)IS2j=m$*)L>Yn`Q-ZOQde^rCs z^NeE?*ZoeP6m4BG*cQ&&{6*4|<qWfpywG_erToh!SN@gC0)h8C2d`WIa^{g055;eJ zvHbOQs3#si@ZQ5LFCJ|9`R&@Zf%}(@&YJU@Eq&wi1@m{$(dA*NW>vfox4*IMhyHt) zZC>*pBlY(_fSZjz`r5hr4<EVW50+i{k4N6^|JPqSCx_p-GV#%UkG<URaOs}cMrWS+ z=u*R(FTd&ReCEF6x0U^E=drIB{3zqe=dSfwMy3rZ{;<ZO{Bwc(%je(uYeC(?8?-mv z9=`pCqz7H+mn1j8a{8B-aKoCr`IC9GfBE`n-&gj%S?%ogWrq@<dqKD<_xqcR|8*#T z`NsuI?#}$5d63NK?w$B@_rp8yc=-I1i!YzKIK2F^)Ai>&;+xJ+{-yc8(z6YZoP00% z&Taj#9=ukW?k@h-3dOMX+e0&!UV8ZcfBy3D&(k(fChgX*VuIPyRK`@$U}o7^O4;d# z@{2!d`Q>}x{{7D9{`T6kPwj7<`PaX1E_-*K?d|)&x-N74w&njizW)+->Nl5vvt(+@ z;!hr46uh_O>*_a_{oh$uJ})0(gVTYsi3{&;Ej;q}@l`2v9=-Hn^!5`r$7fG&zVb=R znXjAnUs|;M>)Hb!c76M4&y5H2FTeBQKcAaDZp(WvY}QtoyKTdRMW;5bE1P^_+1JDQ z6Z1O1nqPkDhC5y@e6013dymvz{@crMY@S%N`E32NPtVT&<=datG%R+1)KZi7-=F;8 zSI>o}7%JX|Sb4B~;)DHP1<y>*UH;X^@<We&?LGLDq?#v>KQsHWQx`kVeqR2US3CbI z>kUr_&;7^t-se7uqa2^Q;(y+K{O8ZF+Vy1J#J$WDe{p_x^1ha}Uj*>}t=NO4c6vmn z*X*UoZ(IH!?e}fG^yrNVnO{{;ZHSl@9M0ZS_J8@>{TKhW{q!Rj?@rlvqc{KiUtIZn z=Hxjkyk=$Nb9Vp4@cwWA_m0W`J%9Ph<=>ooebpny-9P@*hAXYNeK^T3wVUQ#Tz3Dr z3py{&7cOn-q5paP^|c@Vvi}BK`WH`>etP50FMj#k%%%J9e<|?FCM0I7jIzD`TFXBh zcW$~eeCF%VI=_CToH4<P+d40-yJOiS<8M9i($^n9@cEK&@4bKNSG_Ne_s+SHfB&QL z2j6)9-J{)?YcB+G+#C7HeUJQkqU@PR|9PPNQ)Z}ZhOU_+q(jvq8BxAEsLWsU6<u3t zl5eDH529l=B8@+N2-j*SOc#BfK*jtK+iZ_kv_Qf2mVq_I!Px0Lv}_fVh15s8T>}}; zfi73*&TU^VjFx6pDy{vUEkbR?qxv?s39{y=5*5IyzW8>X<Re6d3doY{^WVR7rzzp$ z)X)FeA2bcI6W(*H40}F1Gp$t<IPjy|ML8D_zH2eA4m;-kn|*xYXm;8#B){UQaOC=Y z?%g+({PwpwufF!ipvkDirWx&4m0oFTn<>k}l*32&XARsE&BdLGF;a!$ssQQG#uTF< zVIbnnb<5|#rDEU~t-dYSvTosfg@2qEV@J->mji}RU;V|kQRJE|pUg=_eL3uEyLXZ2 z{TJRDeDJw&AiEyla~oxa*JwA*y@3^FPu-<;wmkptJAdB##~T&u+=VAwXJ`Cj=npfC zp2rVzM-^g_fm3Zq_xCX3Dk2y`;qxXh`a--A5|gG+HK{4qEn1|cy<7Ogb7AAsB4rA_ z<-nF<*M%CRVm<JmKe_9P80#%mDQClwwQ$&{6rL*h(btci{YBOf7v11Z>S7(Z&VU8! zj(dIA=CK>F<S<fiEK6A-GdGMpi*7xafm#)`0WrkmP8P;6*NGl1Wi7f-&vj|BwzJQC z^@H=T8ci`zb#?mqrtF-zqp+Qtw9wxB?#cC`wZC@St{uO4j(#E1bdN5SXs!SC`%N3t z9nR3Tzhksco8aB_k9PyZHg@hJ1<M<}uc;|DdhImqdDacG-g9^H<#$-x&8qGI-xUvj z*ayj(xbF!GYpeg7g)RR*GMct_73nq2xsI+O4hsx+HiQ4r5r`!Z6Vv!`gNjPpz1$y= z@m2M-@_t!^x4(3@B@@!AUxzgY`*h4OZ@hyBOnY=z3S%u+9K#{aaPO~=a2JXn$7~VP z8auoDc;!FYw(TZw(vFw%fAo)&58-TcWasB!EqX6M{?_i`Uv@pYCO@=#l^oPJSBv6Y z`N^rLo@?E6wr<02$F*M0=B>)bQ}2AV|KST~FWlYO%jC-Ze7MzR=e6KQ^NTr#Pd+~s zinS>TMvt*JE2Hkvo$ueBi1-jOo$K!}J^5djdD^3&zZQSxg9k64{xJ9YH}|=Jed)8p zCHars6=`ZRMW4OX=k{pP!gtBkuI4}Tj?Bxhd#B+SJ3V`nR)&jMqggupqaR%UWV!pJ zkAFXN_tDR;4L#YG$c7GC4cc<j@W84xMh1M-s-88^c;eUh?)oFYvleglw&L0x3Lw8D z&&WvjNAG^mp7-*tw}xtSiiatMhYwsneg;SH(YGHPTNa=B;ib2i|Lgk)ZkXl8&?j`A zU1JSQcjSda8_)mn;!8K5-?;muHSax%^!ffz?|opy`)hS==Q}P;&b;r~*lVjUJ~^^y z#-Gk*%{XTFD%GbFyvBg(DfV1H`_lcdUYtCB?3sHHE@f#~@#0l!X%1}m#4)-eJ+uwp z?4b`Hes8Ft5whWLuiwAy$dPvEpli_Z{HU=?KRT^2qAcEY(>FWkvoo^&19nQ*{OF74 zcYgTjnnhJ(^WXmLSJy>~JihM5Nyrqf$PsA_L>;O4D;;@vy?<lTFiup~!rF@8FI{5_ zCoC#?_un-fwg<+JjqU&DU$4HIf76|x{$t6Rf4;T*PtU#3Rg!HC_300M@RqyYtDWv4 zR6qOVqIv&)m*Zz2mA>)8*!i1YedML<w%^@;xo_9TgUeseI-hgo<y$S*2hzX4X!qsO zT@UU1;f~3y8Grg2qt^<)aaJ9EF>I&iQVbaw5M>K+PScpZAbx%u3Qcw#K?r8<31j?L znh{S&=r3OfyiciW7+-A&Q2*ZobDS|Az>hv8g3Hn1Q+*$AKnc;L_sI@6F#b%IbI>|h zfZPsiA><d}hmCY1K38vRUBou@)R;@_>GlC{Z@+F~o)3MS?#-7DDZZPV<&kB0?QjqC zD%!gZwFo43w0%4+&lb_&<&$DqXJ}rngX~8S91WY-i$UPy5sDZ?k;botMWD}!Ia4mJ znv&&dPTxq71J}VX-iNYd*Mi!tfo;uq+MK;Ez5$`sVRz7~R>+2$;(*TLA>2OMWC<0g zr9Eq8iz@~BTn}<Shsn&3Cd|mh&wo}c`wV#eUlpYC0dON?hZcI)k!+nT&_cQ1vQw3U z#P;fm|En#oP}WMLy-0zD|8BQkaav{Tp<)CFM*WH8>m5BhrYB~tv@3y|-?mi|#S7R| zJY(4P>zj(J&BhZySRV~PTg`@@2qt_OfVl=0^EB9e4we<eUVCkpVSJ%jniF#|AAvIv zV@+B4$);x>$2DzP4XMM1TCdlyM5>LmW1qcLyo$$muAwbw<F@DLRdFp%H>bncwjC-i zOw$iGxvaR2iA}B6@wEEf1LQVwFjKnkQH}qE0<!Q-WtsUtp^DfVHVkRO4pD$?5`idX z#=WURR_sdI@ct`j9{ky-qiJvY+@Wy)^umpn%<IGoKq17E9XLI>Ey~OvCygWuv5#}R zDr(#%d)39s-94j1)0$X)3J3SmrK!>s#V1K{@eW5oVY#~AUpvJXR%dg1fBnAV!{Ec? zV<AE+HUtj4hRLzETYX7gox52jdG@74B(GWw*qGrl+QndVd|&oV^Y!|XAW?q!9>%6v zvj7YB>>~0?L?1>`AfnNmigUy1zZpC5^4^uUJnyt!7gL>nr|ixSY2vFfXvy*X#<*Z1 z;XlvEeg(Fswgofrn#aeWh@qhX^&P)fMfmLMVK&2Co~ky>Bvo4B@IAx5KCi`xt&sVJ z8!lSfp4@P+srpXl%3j`o=_J_TgCBlWa^SUB3a)g|c(i|h=h?JlcQxO|Y1tUPHky7d zQ&=3rw)E2bFcA$fx?Y6YS!^(x(8i>OgI_<-VqMi0FXSHXXv!Kbv#ee4n^UZs@~=94 z=<MoB2YXfOiwlQcBv4<}k?^=tCdAQf^Q0E#@v%7Ln(!jbNr##KS`g6jSnVd3Gf|RZ ze`1WtoLH>4?U2K~9&3kmE#_2|9K&sI-($9TxkXV&>b|CXDu0*!)Zg2eZhT&2_J($B zyWQd?{)d#JREMIof~s*&%f1Up>=-70pB`{eMZ+@7h5ib!JN*0!UEe7X)Sa7B*>KVT z{&W;o*qmf@0z-`P`{=7R1R_-uO*{(K^-Ra&n$K&dzKVDJk1z@`cXKYMPqB?ZE!%e} zJo(%X_TMRS?I3@4W7L6l4~hm4dB3~u?I;zjV}+s(>^n(L2a{+!8~JHb?VfPNL2cmM zlmP~04w*x%Z#W(bCQq+OY`i!$Xw}&@81b+~FkoR-3rvJAJCut?-9V__OTUg>75c(P zz`(h#Wybg>p|lcEu6nJ7%COICg-~W9>F8<^Eyn}{m~UFh!++%mh9vv&ptj19T7jcn zn<IR*n}Iy{PoD2mjMNtVe$han5a(`(#wS)dR3p44cYUmb{ThKvg$<gGj`*YEhtoAW z&F%!&RQ1v*`#GZp!^sVK+5VP1D+arp7}(DqY|~Vx>&YO5&SV1We!Z=#ih71Xsqvu| zS(uBxIE%n|0=XfDdu%Vf8k#7Lud3;IHJ!e0TsuG^R!58T6%*0PPO-Yiav{gK(Qcxw z`pNUbWP6f@y~3V<OR_Tnq_;h{<~sh%7j6Bd$B<ssnq{8mF#;ef*@=54r8zupxw7Q* z>5xKnzPwd657k7A&uwQ-%El-Hy16@=a&68F@{%PDkZLo-gcwHo+w|2bbsA?f(B*Vl zCv+7qE>Fy3M>&a*dn`UA>KBO#KL=3$r-b*?YerUV5zRgDv8V+b9L|B)6<g~eGb<%L z;X@ki0eA{LN^`eAvgqKQ`iem8C-<&Bz}_5cT2m~<stD<gIOHKmLR1-IblRb}SO&VD z-+Jn$Vw<DN>&+ev9iJ6dL?oD3aV<%NO{a&k{sv?XnY~7e$FO!NwDI}k18?6T#bn-! zDET3TYmF~z)(-7$O-!~arrIp?ap1t7Bi7*)p?R86-3Qr=Zb--T8h*GEkO{7t^;9NI z-KkWk7_Lo%keoVfHHQ{f{xmYhhH-Ul<x?LV`((KM<A!5ECta_0e)0kc;O$S`HFV~K zOaILLW^u!HPyPA_Ew4@Vu0zC7^8Vjny45$$q#2oV_=%>Ww+1uPF)9ZazW#wzzq+Z| zMx%qZM5r{wWIkcg{9@7DyMBDVBTw;JLRo(E-b46Z);$*($}TQkkWPGX=%-aEdaKjr zF|G>Ly}fJ7<JEWi+7btCh2smOt$PrBu>ng;njKYpln6DxrfrWi)U`g@8e!6tzCbm< z<sq6JtDisnQX(9<_i%B{;Is^+n~aZV*%Uj?=HBp6A5Um}>B&XK2NJb;)2gnmh+(hx zgt7Uht?6E`SV+bfdL?McI%7_GeNX4E+{x*IRrv67mjn6NQy)cHO~4<?bz`R+m573k z8~Ik~Ml@2Sm~;kIw$2^@4Grmq`l2-HQtiLLT@bppge&r^jIQ+Y-C2@ni1g*`8iQpB zvjvDPBMKWywhOH>I>lMNKu?2eGKpc)P+%^x7#&qc>Rib3P|-%O5tUUQe*SGSW<x3! za|32Onlx+@ZGn~*#sr@dExm>u&EecsfIUx0!@~AnuqyZx*;_KU70b0CpHa5xiq%0v zx8g-V-_~Dph?TlDnCu%h+IzOTPFT5JW=Pc5MJU745YaELS2Q+;2Yn&d)8I*#=0Q%Y zY1KrwN|I>PL=+8!iCSt45yi$_UL$KtIrFZ}km3}^20>y^$;^hK(*uk@n5{4kl-qe7 zel3H>6h(&dN#uRh3&V!icCV4>K!-*qrzS{NR^qCwROrR~#Oh4e4r}Az)9)>6Ic|Vu z4=Z7Qfg^N@DmOIBGq<IIJE#eT6{oU~FdNxR-pE7_h2nNx*~b@xfiI*qsAQR2m#m7( zqmXpeW^u_%sx)cOdW@b>`+g>l!itIU!`j?IbcpOJ+itNjn#xjRlnS(fxX4538}vS& zxsGj;LSxJH6VEn8$>d{IO<Pw~!N`(rAJyekq=1&SG`x1?n-p?HNTH<wE#%-)Re`d1 z1>$ZIb;|p?O*Qp8%nEA$J(YJV&$d)K3E`zSuiFnFU9C+(vPZzEK_cmISrO9P#sj?g zlBPQSdJ9gpjw$#Vwi2c_B4;XASSeyYjN8RY6>Fq`2x*)YDA>ztb!~N3N(G~#+y&U^ zxh*vuc(c|l_Dp=doFPMHuEox(9Avlq>k<b;d-y)4g(s8Ok4&p1{YC`pNem@w@%DQb zIUvVSIYHfkU{gGAy}Yf|=^7gh(<c2&?Q}cQc}Q<_Mqe9!r2O(j<?IUmnB`BnlRfm| zCv}@IeKPxE<fDygH*R_8%BKUD&z;<V@$SwChJSK?TbAy~&mTK6-1*Ui2OjFZC#v5| zgLjc_wpwvqbVfbVDZO55QM=byH8zhKcfFQ6#A{Sii3}NfgVUw~Kc^wkSg3%sk(kZn zM{k^`Si%9Ng3lgX-%B!N`=H`lXC--H-mW)PVvR-O81fnVW)Ta3V%i)iH-av-2I1T! zf2z*wwE;QJB^w{{X?sc{0@4&MJdkBfvKUOHj7aMqMPsQ*kU|m5I>lb-k#?HcB4_oA zg@NQyJA1HsRGYTp_^B#KvT^C6y=40;NlKiCn`Fy2wecn%sYmha_9}sVGaVSG2@hhv z6D8GQmKlh6bBrxfu$<_mi2=Gcv-gC5W7EkRlGAKSP--}0>uEewJ(6HYLM4oQP4<LA zF3G0A!HBbZdsGcfz07@w9HyA-ieWUE8k6;68CV$-Ms&6`kFqjb>>SbMhPWp|aO~!> zbN~~s!Zd{Uj-v5>wZYkK8auoF`lfHg&X__a0$ddpa7i?2ibbI^(4dZIagZIlcDM9X z1tnEks^^GI9rJ5s-Xx75JI~~iMD&X6IKdWIW2@NOw^bX-f?8Re)9Y@IDO4oWGd$VG zRw1u&FW{>A>Dj0en=dw{c%oUO?WPUA9r)+<kt6gr&*6TSv0b`4S++Rm#ArKZ9}Nty zi&U}{XeC7dX3B#^)TeAt>9rzEYN-LA<ej<(b~=>WEHDTiirH+Nsi$O5I17)tTDoaP z)}^w{k8#NYrRRu|hs)E0dB)@saEW4xW#&49@;d$l>*nFEg?T2~l^g`#nXzx{X#3D> zXU`q+;u5fuiKw<<lEfo<aM=Vd=?+B!PEijTr5O8adcNBfeG!gG4Khe&D4EivdS6Ws ztgr|ps<)v_(vME?)>$IfQfVHUHXO=I9_UgGM657Y(-acT+sWJ`RjkB%!`0AqaYzO; zHPo7HlY5Gu(!h#W+1O6W;{}KE$TS4yS<4!CvwS;M>O{|4>^Xf032j=%#CtRdnvI|g zPl?%8=`|LE{UEQ1VB3Ghq|wg(>>#EjBR7}5b?m~qhM&Lu$evpd?0)Bu#Vh`B;lIB8 z`}J)pzx`^%pE{0Sv}9iV^vtDm1E=>j1n!Bg49ismh&<sMIKGnOHyXrrb9@sYP~-rt zR#1~2cK21elcxe)ppbbWU9sm|Y3iA6m*Rb@&UTQfd<6OhO-~kTJU$*3SE&ne-r|`9 z`(u;SaloL(GKl2{b@Lcu75iLGFMYUJXE5<vWWFMO3h%qj!mbqbNGxn56ZK)WOOBV> zzEg~o?9b)LE*xLT9|Q@&VnHhP{iPXnU4RWUZ0HzVg$cH>Iot5RWK!l<WN<{fR}MZH zD`X?v0rBD6AS*(-V`!hmeUCh%m@m|qChw?<DU|ArxwwpxSoJBr?3)Oo&t6RwOc-gR znpRjfxVs;1MO4|byiiHA_rwc5BDkv!x+;|fEW#A7##WFZhU8*=J$=FejWR34HJF@I zoDHwkwzhY#)Ur9;pozvvHK0kR_`+V&dux&{W}VBI_~*vF>`|9Bgd6}WlY^1c3cb(W zT&J%dD+)+q&W1ytjn1#I5MhftVUur8lTYaYVIcn07Y#G{!5bR)&~X}^1}Yg4-(gF# z);yz#>T_gis#1{)w?N&ex7B7{nAz5|b)+5mq-o3{c7mF)*<Y&xszub>d@<E*@E8Jg zWddAL2hn4hs7w<_vT1-d^eg_j2Z){LEe`L!^!E<4HHPu1-AVny>|01YB#p#wy!|ys z47+E0{G6SwjG)?Ez%q!rz+)#}KDP`VZYqe4UQMYq(EKS%7qB?MW7^SVJ^;sT4@B^e z<?+BsyGcW9Xm0_8tE5(vnWU>gzZ|ggT~g5lyG^d564nU(1L&@g;?l_Ll=2a!zlD5- z+p|Y{X<{#HyhoQdjmZYlBfC;qx#c;`Y)wLl$2xO{LqmP45fEnBW)GMC1B%5R$s(E> zb~M#tO0V#s73@RJ2>f4f>%SBh(!-~!aKP8?)LlwpGYR(MuCW0Zy&uI32JQ6iG*YYC z0Ues>p^h%8+PWdx3wT5XI^|+IDvYQ)#%tx=5nlEv3nMMx{A+mNgNOe5LPcHE!KD>h zTOa)F#Js2fw`J*no;(>mclwt6FaNsy>*wYiTblXiPkn41Z>a$l<Wbc097!$YCd6qD z6q8dyQK+-!+bZew+xG*@;VZ7NpqHz&lA?@HR3E&C{g@|g<C$D_OCxuJIz~TQk&sO< zx4xP&2Ig?*XpG~JR;Qd$Nck0*@Q-L}vm_R9VYczm3pq^Uwo23!>2##{@)Xch?#T?P zo1~D3X4qApsN>>{l(8W&$aSF<mYPr~GxZ`+qbjIC0~lUpm^|Iw;ZW&)TByx5rLSbB z*FB@#Y9@5E+RKi3JHH5`KP@&&62XImvXvJ{C1a02?X*_n#4@uQIHGqYpAn=7nFgMA zW2cyF4O(k8Jvuz}En24)53NFMJV!TB>FlL+z-g0LMY_y<qOKp!lgZ??ffc)Ht@zS1 zmM(f2ydTY8Wz*RZOC=a%qnl~E$!un$Bi}4_62jf!5XO0lgM*y%-qUxiXVA_bDZ&P1 z72>V$K?N4CQa7BIF~!xF)3iWeJ(aZSq(E%kK2xk~F}24cdq-0jMxVpIz&drM_d$fm zSNC?<My5E|5g83}1u0l%e~my_lm_nkf;wYfl+r!Af;X~+Z=kVyl<JFl{#MVXZTKiw zm`{ZEbXl|-twzQqiVix7zjPUPJF(JK1ionq_aDJ{X>?jsiq~Sf@-stasRA8@XHuuA z-&-1jxjnN+G<rX~EIMq`P|6m`;&^&}&vctf>Vh^{PW(**@j17WuvJ?bspS;OIi~?# zS=1mp-wvnr3sd9i*$sI{F8RJd0KQ6)I=tV-L#d8+o55==4NVIY4CKtYl~^``>S3Xv zC$77!35Lo#`7`~xT~jU8i-ADP8k@PHY5U=<3pt~~rt&n}5s-Wf00UQ|E{mo1&D(R> z*uK-rQ_fLFCvp_6*~s36%MSjJ9^k-c+)KV~=)736IbN5a_3hzh<z<f*JaqcZz>ZIL zd~nT-H)<X!KL6Hu|F`3FF0mx(_5EM{1qIgcUw)}LFKHS)AgGn?+;(T<0+x^KjN@MH zN)(r?*B#;@70L1wZh;OD(kxe|mYBLY#}?xiIvdBf(Fr*8BNO$GlcT}LsqFZkyLcuk zwq|?M2y2eVJ%+;kA65ph(bgsn^!FnDZOPOm&+x~!sob5*kM(q_cF*J8te+>??*<Cz zc~1_?po21=zDLimJFuUr1ZJHA1&*Fh!=G0J+ev|RbbnEr)Ur~|OYo#vrWZqF+>|R+ zVqS-t90SS-!^~avD`_lHQ@jR3^eU~{E9o7N%$7{Mp7=}wNz7FL=~R|hvpR>(y7-3$ z*LoE;8rs87sfEF?J<$N~zTN>KN2p-q?zCZw+}lQig6zYu=2{tUYt;a=%IFl~BTFsF zW)9H3$5$i4BZIqZV(t{eKb?h{*4;*C%ihsMWx@_x%AH%N=44rP6Hp)|Iho7`V82J! zN-<hMx#=6!p7JV&qP`lhzokBA87QjF6{PTbM=fh>$FMcm#y#3thcSS5p@K)x4`ye8 zq@K=QJPW9K6k#Dv^C<!olt4)nrCzTx+T;l6Y#KDy0?^T`RQAm>R2<Jqb%xpjD|r)^ zb?Dz!;pJ`(_$-TuSy#y9*HoTvVN0g0AmrQU0v29R_zVvELNV|>f&S@!*`UscKp+q* zrm#$ncQ^GwWd5v2wv?8-Osa?A)l!}MQ~K?^$yEu1lkXkAO6IPhV&YB@DMZ}w`Wvjx zKrksF{P7No-lW4ZI<N$PzTRRbA!`h^rPpwPfdFW9XN_*CRZUrk^adQ*ss6Ur=8jBc z`y*AQiz)vk{ftgiUom&w9l?hnv2iLrR7^2?PVjfs;*cgnV)(&itkcbuB;t*H(5xiO z2(WozOY<0zM?&NLGru0ly!7VgOUIYHKRJE;*s)7<Z`c;UJo@>;AY#SeFA2Wf@WbGi zv{$!2pZNHluxdbnW<X%2u<2CKkrT=ZmtT=x4J|BquFoChtzc#9&eZrXi^o;g=!8XU z?ggwK<;<{4Vo9ZnI4Z(<GuSlm<mrLYDKmki=|w<eu$guC^7(88%z+g~Pvh7Ybhmmr zltbK_;8Tq9A!*}GtNMqlPUB+vB8|dWL2M;S>D+t-{WPYslWJDm#5!qA1rlb^gFcti zoBgI9mqkbjl8oRSBEy}hP68~aRn_=4-9R`ZKc!!Mc{LrQRM`rJE(OGXQO;5JNY}AN zM?=VH0Iz={sbR>cAac-!SbxE<<AO`lSY_IdqKoyx%p%IfH8)AHVKu+e2sNY@9;9wE zIIE`;;bZJ2+O<7LemHBfj4`Emlief5JWjmoE#^w7B-W+^9g0t3@zNAc^>#}(-++XK zUuAA+E1aN^<nhz&4qVn#f{AQvk{4c#Jpk%GrYw+E!&R)`<SrXDBO3y!V4{hQW0FE< zv1VAR?7m9?jEG}UnI18Rim1ua&iJU9`#LK*e7#n^E$r-dZzg$0c@(#(M%+wISgaKQ zj`K8H_NYi_o7&2QBt>-z>q9wC44RNz9Ags2s#9>jaJ2MW0YFfB#Ia8aX*k29W!bix z1%S#$La7XcFw(fJ^Z8Q?&B$$L*uu2B18a=T$D5!%9ZCXvYkpYCVXiD)4+tfN%}hZd zreFQ3925<0U*GgCwfDdJ`5&sA@BiT<Sv2Ai*EKml|KBAh3dJ|eu5(W36$^|sXoA47 z1bnHOSbkcsCmOiJN=$uTL0d&uW_m?%F)h~UwDHyd{|!FUxIm67AASaaL5QRb5Z1EB z-*S9(nr0-sKvzAMPEUW(nT+i#Z_5o!NdXJbmotzare@VRQic1p7SfOrsj}c4*`N|u zbn6Kl0zTLY;Y#Jv)zak(O>j#ao>8kzdE|^|BM!}?BWn_G@Y;bhcT{B=60${HTNFd; zlmT+LfMt@&#CX~Bbc9Q*_f4h{GYp)ocIj{^Efp=>-|2p)lCdySAEfr<Zg!kVu$qLH zXSr(~1teoM>^soLthikho*UUJJZ1x6$xzg;R5F}gG}sL;EU@%<T9=?;ms}|{r)-jy z7%X*YzEyflwRhQ>>n@MdmS4pr)Vn%y2uF8mm#(@#QHylTP>!HZia(O8v{gKwJDT0R z{qP<I6qJN0k}ZkNS~Xk%3^8WBYx^PDpUn<>nS8rN!Mr8g5Yac%lUHcy3PVLPUIURP zL&rhRAWO3sh!Rz<2?>q2j~_9}TEgK(zXGRaQ}P<O?*X-mxogbY)~-#E!TmX)&P6Qh zrUz0B(Vm*y<vM7c*w)*{WhY(FARaCZh<bq81-j+<V6?qB+Xj-ZjVms;<DHu?nO5#S zMoWsOEo&V#RWO+ijuZo&7!T(8%z1&?!ctH$)~n;{8;ok&EmU-%#i{W}<-GxWz|sfN zd1Z}OMT$w#*`aWfE#C-6?6g63Fl+!i#Z^maMB|GfLnE~U>Z&_bm6EDe5)450i||5Q zYGTY*I$>EV8Oql9^~umU#tpPPQ0w`&3bu-@GQw3DG}N1wipDUk7?Ez7%z~gP$#Q*R z+#_9zm+N8{b-@&$J5t;tI6o1N7?8&g^KYcVTEp}O0LJJ9BD}d*!(UUD%|xOTjN-BY zp&DK~GOANzoxzKP6`!r8hpL!JA#M^K2;0($@)+nfNi(W^LjC^81XS^~_=91I;nRXj zv@|3d6KF0|aqQEJs%^PF#_6D5r=rN-t4EA4cp#q$6T`-_0zs{qt@Et3fNtnQhZfSI z@_lGCq#x%^Q)`&{O4%;p9LNxaC!)ZiA!q|E-$@>B$>X7j_`-hBd_`;L_Z@ae7Sg<g z6Gz)q#{=HBx_JPzkTL?+IRdyt1%{JtroaKccKCWd1US#7#3JBPjtMUnpsyNik1qvu z#ylEK^bP9F0KeU66ZkFm6<gpN$)~ESBj`ew?Fxkj`=R;7vf-!~=t?5YMp+qGw2@ze zt+OUH<oxo=Ae>$4<piTxl7vcMD@rg>V`=022);3Qgc~CyvYr4zIR)fjEJZE_jY>91 zYa)4^Ke9ayJej2pY#>E_NX5t)j9Qrr$3|Ty1x)*X!R$%xX}Bp;>xt|`^mCBaNH#eu z5kZ3nwMgC~WOk{>6t=pz&q0t!`ZC*)8M!p{358-WD>k&0_?-4GGVtOYFkYUmje>{* zB<c|w1iS4@O=~e{aQa-OXBIdk5H|m#V0vGit<>u+nbQhEGmw)|jc+ZCznG!u>CKC| zuQQ4gY=pio0OxjdBLFO*hOK3Vd$ZPI2OI}5O|Gm<QhG<H<Z!vW#4k6ViJ3tN;4sez zAw@GtXolwS4f<R9HvxtbL!8jtrLGDxdUEv@Yt&&L9a>nxHrt?4sf71&L`q%Q<={1i zu{92M<QtGIY44@WNNAf#v6`)Y@q&fnQrGw<hdunwx+A<H)K5qEM}qf}y;rLJtbx;A zSg7<}qSFf|L#|VN<!Tc~CwShR-5j8UGd-@%Cj`?;!Nr#WCFlCavGfE3a)=JUbTW(} za9G}$9Ok_79ws*qL8C(I;oJ)%aK$p*!Im#xJ;t3aa|FtxUlpBhN%rVaAJr~63c3Vp zr^@!#?#&|;Y#JXOBFS$-m7sVaX`n*nAjZE}+un!4Z~zx!Ta0@}BV*K$PO(&%FCp~z z$LYL^K(Abt5J3^DUW9pol&jqH$Cao4XC5o)Z(lU;c2m{0ciHmpy7h_cpZl9733|bh z(A%M~t*kl)#%%gFCBZeiBHeV78ggbgGfA~9wJRo6M0;ww8&54vuqjZcN4=081cjtf zsg0VjrT!4S{}OB{&|v_`QP{Q{9i}3nLU5s_sgy>cT%ToRN|Y$+Krx_Kyk7TI%Fp4^ z3Gox;Sk1R<1{HtH41v@EZ4~?*sRyoDB)-u-tixLwvXHYPo1o6kR|7I&{Y-^NJHC%} zG1OB66rktH=WOuLuAUa!({lvC!yn&=K2|vyVp9~6Pu+VPnBI5f<Vw`5giP3}RtHU- zIG(iBv$|n)2xQGe`O4%}D2s>}q)8)Ob3#?^l?Dl%gKmje?yj#>iGY<D1Cq!@yaC#& z#u(x;gld{8rsBr&)50EsNwgi0)A)pn!vKLLP3?V~1o{*49IAlXG%HF)alToXU45!Y zbk^qV0bp5@fgm@qSe!wo``5ZMr%AvP(~n9GC7*=u8kiQuJ=}X_v#tsaIA%>E=DRL0 zG+3Hh8>@z+BU*rRD?QV<q`^_sPP6E4Q$Yk#;!ZsPjut>Mg965m+pH89rGlImtK}h) zRCeQ50MRxyof52aKI>VHijFe6yDiHABS&{J$Y=C(DDe)$A4ifBZIEKoHkW@tPwBPV zJ>uZ3P!X~kBy5(ivjcefM5`uwN-Lg2Wg|-=u_<e0--ZFKo!|$>?-qcQOD^^)*wASD z_$kvJPSA7%(UZdHI~evmnoi|$dTL@~ouEclk-m`*5yx?I)tW<XUBH+{uiS+~rA$jb zq6HGR46Lw__RekJsPe9uC|GqERUP#j$M+QhcTr*S_X&Qd!Kp|*XkHKo3U8UA^9#D` z0}Yt%q5DPSsBk2;X8Ku;+B5BJU#-=*C6cZnKqzczCPxtmHK+La&H)`j93miZ_1G!U zbpMcaD*C-y11HfH#RI+BXo;xyrQ95Fn7xY24|qe!qZUcBDbC(a+w?vzB>8~IQLE7y z%?5k^51~+O6<BE3lAs*JP{}jBZSCFe=F;Tp2?ksbDOv|IH0(m-m>qPk6h-vtM0PKX zP}XR+J>1120R9x0nmyW_dAmUB+sp%qs=x-2U@EvB!LtAe7Alpc_aWs1QQ(ZRl}*K5 zrCn4|k+YgSmoOO{W%`qrlx>L{$ZD+kgE67z;gg9JoS4ffhxF=5{n<oZ(!`c{brg%H zz|mSvkE<A%6}^Ll=Ti848E_z`llZ!A5-T;J2ie4FHg;+-G|h&&Z)lp@s;L0`k2@O> zZv>Dn$n>cKO4pF8)AF1Kx*Ah%ZydXYrHs`67K@)X_9=PH*3ut|z$!v(Lb#fNIVxL) zT_~Q8wC`8fm5|+W`{8{Mjb1-JU~r<vx5nLq(q6HYR7Jqt!T;7V1M6^J$*w3(t{Ge9 z&aCKzEX<pH!N;I%`~EI}OLOULoZXwYXJ<Bc+4654+0a*#y^a^svck3)^iX3&4a`rn zBM|Y|cCBCOt|yGrptJiH&|B)U?9t^+o6x}N#7_;NGc&1idlnKqrJMg=H;7B@MY8fH zy8{fC^A5{4$JIENLDkuu;<b@vwG|#)f`8%c6Ih=1UFzvvZOgM{YKPsMrSQ#nif~l0 za2pG7Q(}DAF^qP_uY`n00;C59GNnwFn%E{xHepXtcIHo_j^W8>ZsGWg1-#~z3P|>) ztf!(;*@>7!7FiT;bT{LAD=Gp#0*i4D)l?12y`Z8oVn<*a@1VU}XB_v8mU(SdiWX#m zg|!6EFo(O#9n$Ev%_+Okifm1WKhg`s)@4LTJ&`?7ly9DUkZQG?FTrcPzABfeSDIWg zWuz$#g4=jX5B*3`*;m_+1^wcgMu(UG9Y!-VIJv5C78rK?G`)C$n@*iYv5JhPkrd7! zM4qJ6!lC1}V$bvX0fPAO85L$@xQaC0+(iOCEThgnvkXXB4b&mLtd?e_FyBeNQRAt; z*hIR{EO3H=LZi#p^=jxbIO*9Zpw`LZ-=wH%MVfTbPr(2=s}jPZyfD6?WsPD5*M~@f z^_A{{KVVEyEQAjc9i9}<l;W#-D(t#oiL^SwwcQ5UG{cu57%=~@lvtWd>EB^VFcD_` zp=z}^wq<%B@Cnqk#AOmFmtSgWny@qlE|2Y;l<gU(8pl?lZa~_}-wm)?dS9TWS!EPk z`a{y5%H@=B3muA<8m5krHzWX^!f}*flPyIu@q0s{C6ktp4JQQ&ROE}9r99{)-O0YV z>_SgyYi+5m5K+$5*5ZxTLY`0@AqF5-qaHx+Lv*L)tk>{wikUPAjHTTb#fJ+Fi4)4f zST#~Xm~Z09N=l)=2x)}86Jp~Oq*bDyZorSaah*|qH0Wwf+cyh2LjdP4V4k9uN|-(H z0$UG5RM=-^Mx|j695mbVuVrM4sMnlAMIw7y$o?{8N?GVoyY7P`phF|3u__2wN}8OZ ztu#cnSs<j{)EiDex(ORqlte=iF(W*b2tV)xqo$1(Bg1Y@v>`;bDGQw;l0?IXWaj7- zB^T}FUecP7GS$Kfh)s|MDk{Ml7}OUveejym3Zg9h4a6Ny8c|aQV5KwxPo#!bTStW} zqk%kC|COMFB3l)t82FGd{vDhE%S<d4P^2Q@$aAM4_G;4zWQS@6;F?o<M9AtjGP%<{ z)w1$%`+klf<lgpdr5E+l;vAQO*AmhMrUR4IlvX4t$s=XGy;hI!1UIJcsF&5R$Bkxd zf!R;%C5;_2e5k0IG!H0VXM0X4C~g7J=-f1M^iZQiMYS5P7jx0YjM>65dO2q!6_C7& zCYo!b1f5p0{5xfp!2Z=KyJ%bi4<Hj@xe4o`tbshBu3-RbGsmfvuS2G>O3NlHC|Ful zk2|xZDd^&5CfTmih}KgyvFGN~JXR!1x&&RaJKHo8At(@~$p^Dy=NCzm34(56&k8{4 z$6@FJ_RywW!<h%=swlli3v;!s?^3NEWPcjMY@+8hk{3_}*buu()fY)Rq!^PkMKwfE z$cC&un7<5D49Op*nt&qmt)O5z)G$)uu_M{LPAxPszo%{z^qZkYbR+Fjo5{<i)5j(p z9G7XS<L(-2MQ~h*jo!9gqi54fo|?vx<^;PSv<b0BNM6IrLBRqsDL}x>5koUGt$C_b zN}XBST`9NnLi6chX832v41LpW<BtxB+{P`@Od&gx*al9HZq5UN#ybKWBn<Kmy60iT z@-^Pm1Ac0aW~tp~dK<@Hx5l+5!hM6u!y*a7wo=H*pE<KpKeB<74Uw0q<sdO7A`k*% z(1BZof0Wx<)^=##IC_t5Y&}i{QsL0X3}C`arNTQPE&CI)y)+WRWRzTem(Ve?Kmnyh z%-VN^JZx)0^viutgFl1t<ENl(hLIu64hxnm{Nju0CX{rw#oQXLlP<E?y~K_lv^2Si zIGsiPIBXa{odB5%9ckcufrh2;SiWO<nj8Xt4QhQePfDmv(bd;DNQEF-JNs+iTqy%t zqDx3%xkG7Jk;#;2>nSlKwcrm!#KJK$aL0jQ;EryWyS`a%Y~<Z&)MXl!7d1Q|WTgSf z>I*qD{DmwfbPf~|J%uk7>LJ*K!2cg;q%=$cpp-hTS1i4wn=>3eaVK*i@yXP_=|K42 z(|34J(2pL<Qh5LT;vIC^S|v<RXVbBzxOwc36ULrP404pt*4kMfadf}1eztst@0+by zkb(#iMlqWpO<WWmcmDMxM44zAc)gdZ7NkUR^7J$L*5jF314V^8!f+uUzZm(TCj`v9 zG_|%ah{HJQ;RH_6R_(Y)i{Qz~@gP9#T7WpB9uu$8?56EWq{N}NMJ&ZAn0*4t1@8QP zvqm<r^1@RzUPL=Lm5o0Gw@}_4U9CQ6lvLl%**G*b<Y;xFoK6}7@%z*BZ5kWZoryCC zIUwh<zNcI-x#ryb%Tw@A<OaCQElRInaUKLNB}jwry9f*>L6^4zp~&qN%m-=z-cp-@ zaaGxfWmUBpI4lpLaVniccn@2P`K=S!^d^9P<CtGD<M=`Q2-+N2g@Vf}zv)F9Y|$Da z@!Kx{cA6%;*9Z?lFr%8#X{FELL!u_dok{inho8xkf|Yqm1N18N0$iWF9MLjqr;t2l z9%=V=yI{4rYKEqZP14QyTNequp}4A3dH|vLjrpiZ_$U*kGp87oIZ&AI_-_VDu6{@q z;te~@ZAe41v@xRw3P?$#wKJxIqRbrFjr{zony^|>R&+s)3l_$#3>Q^;jA<YOpk#GC zCb~T|eLxD}eNTwoMz$=<umI1TS53%HgX<D>Zfb-gkW`hb>}bONK`^t`7E(kJp1(k( zDCt}S+Y~d4*vsI5qjiGovkBF&Ajg`TJwVO`!)VhG$)sH1=jd3<D%V4_k7y0KW>`Uh zRG>I-M*=~aYjhd{bH`UBOrSUiAmv}f;~|%n0)l3D+$%6FNFxmDRR9oynVL9-Z4>5h zKFL;UYCPpZ29}D$G4(iId!7PuNrMf+k2Kk0YYj{Py%w(t;sjmHI#{i_lt&OzF=~iF zw_<cEbdCCCI>@FZEucefF5w*ruI0E@w|*};q8YKa*H)on3)o8O!jMVrQ8x631RxF9 zCJs`Q$7GDkFJFo90}M(7-7M2v{xq(s9^pW*0zNGQ!Qf&9GR$0dhw5?_@Glc|9?A+T zrG_EeP$${bWJZm`_o3sUJ4K3BNugZ@4i(}R<=UXMZv`-E?>5>IU%BRnsW$0UzL%ht zWJ~vF&SrONB}fjPxVXFo=o70K^vx0lUxSI_84hCRdOsriCI>t2Rtl)hfFH?H<a24r z@udQjNYfg$QA33490`1OPy_-7^()B1)nZf_Q4xwu9u)S$C1R{0T1@Z}CQ$?phmk@{ z2o)Bl>C6@@5ZJY0#+@jFnS6v97wS@~JZe(L4Um~p%rb$~s>uVU%6x*}9x*-V5vXPS z(OuiqOV^?;q@6=XaMd7bhR$~RLGCSWRm+NzDdx=Du1y7%Ss19bK+;!;MiMB+Jg^2v z7Q`KR4*eo+eoMXCPb&+mx6dKcKq@^HNECVCev_YD%_?rjo{xcao(P60iF73z^6j4) zDz$_XjQU=`c>qul;D0)l9G)iJ5GE-c1@Wh64#+5lj1<Ubp))7hL|mq|$2MiO9H;48 zOWxIS)QNs2RrCy;>DLkrRI`m2In7N8{z`avpa2|;*gS~8e^g|unDtCD@lL`=&8f(( ziqS1&Cs6DV4Qr(%->PxBfX+(SLjB~fcW099o5R7&3=e4h`PcS(K~y2#(3DEI@8-F+ z<k_6GMvUgjJf=)BaHY`%Y)UYoR-wk_r6AZ-<25gg&zVg1)m;9g;mMo92X)}#gD%BD zP!VoOtsFShw+W(2h*$V>p1|k?(8%JPQ0ZbVV^y$4*kVKL>X8BU9idB>rWMH$aO~2i z1wHX>YR-Y(ET1>~!9Q8JR8>cP4z`Q%cz9I9(iMQn#+214x&6qd_}Pb;9hF8-K1LZ_ zf^`^5s0&0F00u=&F^%g$*Xe;?UeBNr*{Mfc8N3gv#B1U9{b3Fc-dxiGm<M*2UJgiV z-$R;00|ZP!`v=TjyleX&57I2QMCVnfyy@3_y?zwK@P6p6ew?ZYKpIGQBp@tPr#~yc zNf~Msa<qccMvd9W?bD*s0ti<hp#a^{;>-WeNUtF6=shh!1T)}qWVxh=(d2&gs>1rw zj7VWCM4;gHqVWWDX_YQklmpCy(FB$e!R$`!@4f_XTO(9o3bx5er~oF!r!g-i;2G@@ zj_+4H7599a3_sRb<KC0BkVmWqK$a%RaBU=<wNmjy=*cWGp{BotDM`FnORtgRQWNX7 z#-zoeBA=h9wB^#jBvMgNpC|f9kOI`Ed`<&XL6j>p$V~}(#8g3)gZlLsB8o{E<XQ0B z(Cty$CHrT4Hf>v|M>nLRu&L@el1Rje)OatSzJs<vG?1k($y$K3=jMZ5PSFaysHO%4 z<g`kZx)6LAYcy|<Do(N^jb~w+vJu-fw18+Kk*EY{uuO_hYql~HLS2K#qsS~>kV*~F zLXtRa<L-o!c51-ag>SyPgC0Z=O*?fx6ETW0A(Tr*_o)3w0J)4qZSCm5Q<**pQ09v) zK?Q617YHJa$|-k>+NekaE9q@)3p)rU!O}DW&`LZ6;wa5P_o3P`NIyZ3fifA*G5TkB zbJj{5w^+k6yKt^M5?ikb(;z4-Et2RZh?a=s)mBO*v6AX}aMCXe&kc$N1)z%5d4=Rs zW{tLTHHAdyR70o8ufVmY`!s+A^f1hirE9%97)B|e0brtHS;?(M5k*nr=RUxCGi#*4 zpFxjM6V)bB&F&*{*9O;)HieToKfJs_8n{U76wzE!2=Ut!Hn%o!&koT>nIe%a#G>4h zwamq;khQ4%X4;t6h>>C!7KX{Xq%wdG=iVSaFH&|<s~|sNs=!)=6w6*9GuKG>J(d%c z{!JjVARt6Vwyo2S#z4;)$}kGr?Xok)Xh={<tK2yHZ;}#n9onx)t*yDniWu|nT+YMA z;(j%fohF)=WV#wn0+=H6N*Zc2cXNB6p^rVVsv7~qakZ;QTATnKrIt+^du)BT%|WLW zECbnbo*3Pba9E?Go`XQ9^6D^B*a+zYw#&HEMkz@6Qg})AW=`Wh!4T2o@q?I7pzx%K z_-^mDXy#$fi{^quA%^ua=Ow}-hJ85oOhcfbx+H*;Bh=bo<L!23MidGUVai(T>IlI@ z33QH2FdXoBi6U^rD*Xe*43;-TEgnWSg52fW79Sx!EwzdO+Bw5dYYHyQR3~*7Xsp6- z-JJ5I9(JETR`8KAJINIoud#fWGX5K&&g+`T{Dp{#kyrMKa)AbryG3%)j(@MV4%1V2 zGa`}|AZg|cIjH<+8))p9sUKZ27rJEW&|p*yNzmhly4*GVKU+;<4?%ug=BO3pNCgOm zojM4oX#hO~eMY>4dK{fIJNr<^l#MhMu@8HA@^clTooyI~(bD0OQ$vtIW{HhKn}QiD zEg=$LlrlKpfKO~|4MGc;G|EUjzp=N&kDd%YznYsJ=+G9=<iq|IB?Ql$29!DsMKV2z zHP&GxoIyiU1GP;o*~1B%!t`ZS^v=aP#v+V@j4&K9AAH&+4#7N@3pttpM#NxXC@L?? zj<DUDW<If!jO?D;oYM3Sb=q>fL-L&znMe1t-Z8iqKWw~VxxS2CHmBS!rq>p-Pzc@| zW*;4hEx}NM*Ndtc@uL>@D7MrHr~?}MrUecKeF?XhGmMLXkG^A52FC%90NxLa4qIrP zLF}6unMoVw#EgQ_j`<T1VQ^aqy0m%FE#%q@tXo&-y?#6hxav>if27euq$yIglrCG? zgr>$_<MFqmXCk{nNpT3IpSL5wmXHx9fN=#V7*{in+}=IN=%DmIfdqhb((`Z|`G*#q zc(mL?zZ8`gq7j3jSAh!%Ac__|0BFfXV&o&|JE@F3mMhm?-5*;VSD_L}aYhJ#Lj^_u znX&j8t%}!y4@89MlTLsuQ)0F;3n}C@3Wbm!_|-NX(i`<sr>hbVY@Vq6f@Fh8u7G7O ze=Ee%$h1^CyTxkjp&~KJGsTWj$eHi73T%5!^<=|5k!{H4u;r9JLn4kK?V$FqcT{N7 z6o3L6m~*Tmg?(csoqutC=~}PiXP^Y55Tr{mdK-~_F^JDwYxj<9pr)bnomOaPc-v_e zF<h2Z9~qLtn3xxqjtZOGM&#y6$&@U0xajsqCir$Es$6+3;Tk1bUWjh9!zWf4H2I)0 z6o)jhGHg%R6+v2lRVKx>oDH>^FiA3T3m3ozrVJGaCHA=y&mbL<L{afGFF#*|UW6`2 z7TEVitgjT{RXU-F-ikICyiJB${V|ug4Q$$0NHxcmPbG{NP^yPf|Dz1V3Rx@ll01AS z@AwaCo*s+bDCxdfolZbevk!eg9}1Zb^z_2%LNpI-K~7eZ#r2kbe0)fW_w<wypOc&_ z!V=#K$TLy2oy<6#lISDxl+tFRfx?w1hVT((3#bDjI8GNV4Ks-Z6bKkWY#f+_M%{A4 zIt)*os|Ye$rlo?4aeA1GtEmI1!TdW+1CAyO9P~b7{J@q<L|)P=R!DQ(cSNcX)F**q zk*q=pFq*N2I8PQ}^qjCNpL&ynvPi|v8&WA`qNTY4!rVbAPF;F=9uq(~kfpO43~Esx zvK(%HA&QixLm?EPrPm0#4DUL&rIu!n5?`Qj@LKkrLeBC>k$O3X{Q_+AK4Dc_j#IIA zyFxKPNwxqGfWD5yq0ae0BlPE_A~2cZ2xp1<#}joD$^aOy&LQ<r-->|+{ZxS@Xc6Ja z$P`imo~h7V{2k36jg1tM%SVR-(-p~&tJJAQ;kxMg+7S2)EuemN{`Gks4_IvC$b%lA zQDPkaMd^slTp&P?mZ!K^uOC=ri}kvv!pCSt*dWpc*0Kkr_Y#zK7||+tK>O;BJHhZ+ zN;+*9q~LL=C?zco@P;~6d?i6tG%N|ILcGD9Y&(Rz2w&??LAa@4@iA63ciiiPPp5lm zJ0w*&;SC|s5~0|@`Y3;tO7f;&Y&Do9;Y<<si6HEgPgaG(UK`M92G%l`b;b&WStjt} zWM)O-lssB^ycOMhS#Wad^c{v_kb!ZJ1kO2Z1(cP=f-kh3B=<03r>my@sh3sPVAQH9 z2}KK_Uqx~JY1Tc<ayXe@5bl^{A-!X|@C@ijj--Nd^-rG<;5jlShj~x%K3X{9t%z!x z;nnHh`7We>rvl#&9)IQbw%}{>*^;Zr2HG_Ai&gcqRJsf7fC*Ws=f3INW4*nQWF}#i z<g$PUAf_rUBZru;Xt+8+teI+NWPE~e(pubHzDL5*RTpET`D|i2h&2@jhs#gSO6`lA zkq>DcYR^NOK&;a+1RdzEZ{N>lT7g0d<Op9Rau3z3?CKTq14l=oRdj$fiklqcj|$G9 zSZnu?d3Xj4m#Oe?U7|sM_>hLuI{4S>6uNW%w3ZDp2%%~Z9lu2KW+b7dvPy{2j_awn zH?QjMWt!F(>Y}HhCzilRt=(ZpQ!GdUY?X8@L~v^9%zv|^_)Ede2-MXpZrU6M>EI>l zfrz_j5RRlJk!MB4k8pycIz>P-uxN2)G7OW0=sm#r8O0+&6HtmTKO<7*x_*ic0#}N! z<4*8$mmv_EMuBBR#GTzsq@EH{vm*l|2mlzVqcW7d6q1HDR4mvPpB;i{Bzq|2z?#V9 z9M~z9?n!2KOKo%_sEQFx6OP4!3*=p+1u>EsOyAIqbSH;>?FuIx$iI?<LFmedIY7LZ zC_$0lBfWr4gyVs|`a!<Zzfl^e;z+D<JH5rm4i7KJ;eoN@wou9GS(6%3>`rnl(j7{< zbK7BjG=0SWgpth*b^u$Gl!{_2@mP$7lB_yo*lbM`4bMi9=uAAK7*=CNB<H|H_~VH4 z3&$|q$!=pN1s$pHux9R6LGTI$?pF=OCQ}K8cZ%rzb&A_49e1{xJf)V*{{id{?XkLb zNKG2>O93qnCRQ0t!n)y)Vq$cHb)ruA5FvXNvZN8og^Fg$+@t{rm#f$eqA{QQJ=-VZ zHV6+Coi5e5Lep0wrjTNyu`RY20dtqCAV;046!u-x8|;dcDQN=t8#ZNwpeiB`P@&Ww zbl=hmFm8Y^3MKDShV@}65BJxoodo5l2qQ$FlO{8=dDJRgLP=TQ2})#n3h;)kbMxoh zr29S<U<_1ZG(6wcubwYFEV5(<beEa{^f|tw=Z90xvpS<)3KJ-`t(YzlF@#Rz)Tn(k z7jRk{^j^?akqg*9NGn1HUMGG<n(75I%`S>2zSs03HqVg{HAEjPMDiH8VzjhkAx%E1 zTH%$0Tk+mN0=doA3j#54TujQ4BH03koMFVi%jG01yaD_I)_3=Uu*->sIiNk2Nw-{4 zsxh#m(y}%nag^#lZK1LX_=3)9Y?X}F1fu+oNXhw4biGJn2-5WSn4MvZq@vDzHt{W1 zHQ!Q1EhP=D1k2hl;R?W-ASJE_C}pJC6pJV^9|vA7`_6uvKPGcEf`v7qq))7tic{#v z$?qyGG>m(WcB7qx{g!%4W-j?o4vmexo<|y%R=4_;kt9~v1%o>Rw4@Mi;Z$h3)bvXx zGgprllrVscylbS43P;bO0ery#jOwtTDRv0LhysYn1Sw3i-9+UNK#-300<hR^d?SiZ z$8g63qM;E@zhaSI1HsS0ad)ODWfwT~hC;IuFfLFScXJ%@dSi!r{<U64V=99#{u$DW zT*d=nE17_r?Xd<DP*J#RXrc{*cjo_;ha<HREbui3INJDD6b?Z8R5A7f8q?r?v{-7C z<ogkJ{J31fNm1nPtixqS8VHL0YoxS5AjKbqQ3N0ynV6aRZ-`*;kaMV1PmQp8m71mi zx~|kEB*Jl=_-WY6v@m*lAo<xILNXmuNKm(hlm(6DDZtE9p{O-Oe3CFItlVw1Jp-=` zY}s@LUYbH0q8>{u_PKNm`a-&S`Ve2V0wJLcN(f~EWk~TVO%3r9cR7CHlUN$YU)-j) z%udE3nfnBVuO8dhGNYn2m-&@m*XWQQ{|uAbRy%f;&zD)*K@84_!2Zj`H(Q#?PUGQJ zWk=1WEGH7cJ1A|g!o;nvNiEXS(txO;B{!!RNS}#Tiy2gjr(l`v2ROx0Cq4}!Mmi<s zSw%vCZ%#2Cv%)o1RFE*uc_m$k@eqoaM7j<~j6ZxlE;(P6N>yDDb>o?Ano=AzB5eCT zKX1GvK;)L}z~jU-m#UecE)TQnNHO_1A9VRsfMg;Vz(whgxiBh#f~x{|L&88?@UP^- z9}5jO@cf@kfcAKcjFV9IwXAW;$5Q9d0aAnpgbc%7Tpwa)qFH(_=Dqy7DC!U_?IgxV z;e_icd<oo$I=Ilsxl}?a(t?XL&ddb_dPe%@A%&COfHs<>lYzGqa01+qL4WQw3JHdv zP{sw<N*v*2`y)y?Ce8{HFeot%wWt#t7cfp=N8AwSWL{9A=%4BJ)}Sz;OCpqx709Md z5nD*MkqItd9-RPm`xaU!M)?&K)AD;xB!S$}8mc4wG4;Qx95{MvoURP!qeJ0S;&nrP z8c#ozXw>__X4T3V=29v;NSD)hFsmXdN95DOml9FL0?{2|tIt;W6io6}qm)TwBmqbf zze0)wwTq*BfDG%uq$UD^ser=JJkSUbYk;1CM+MGA(8eHN46urZQz#0BB{piar3x$v zy^P%RS3f$9z9T-kQt7LhZ9%3Ez6%w2RRcpz<=@~FFW(4E48syK7Jqk@-&rn|9l4L6 zDpRjQAc@UXFFhZ>0_@&XYTSK|T2GiHfHMTj2pS10^4^mN(&swKs*7_5afQP)g9oLj zim=-i$fhPPhCgQGU^q-vt}^8(lTzv)YeD5jiKKQ_M0=8}+%-BiOp$1<(O?D@OhBc% zk=_*XE{-*%C(0~odr0qF`J@1~>`1MG>%=yRj%6!HfS@{e*I2q>w-LgRP|XBW5-sQ= z<GrnmJa`!?3|S#9ur;6JdpJ~TxTrZrk}1F3G8wqj@&=QU)4nL=7$-(G+!t|*bcZMi zyeFhE-3rfFd9<5+$NI7c-e$cf&5Y8cY$4E*JW9e?vYK(2dy$7G;Yz^j0!dr+-NbDu z)02csPCF4!S~)y>7^s2OgRJAd)8h*#A+tT|%m<w%_Dg_WqH>zf^F=Hnu@Yxgfje>T zn>s*H_hP_-U)VqqHqk<9p^%j8Jzu6>Xt+cwB(nILI+A(&ety6$C|<_iU|QR%I9=;U zs!*BItKbMaG9{ZXhD^zOm$cHV>Nz$@XL|WY)oS3vOdqp+DC23Wfh1`X<$H>VPvb*< z3q?^<m1u<WN9z#;2t=1fuaKSRZ9Bv?kj~|oo*<F?45$QQXeJK}Pb8yn2_hiod4YGn z9t~cDzd=u@bj{QaV~ld7Fr49!d*$m8p2X+V$dW1;l0o*kodJ`}k~O4bk`@6LQ7A6G zHjd=<2)<<ld9>d&tn~F&)VVU=xd%T6GC0&u+-_<vpEul5?Z_L2yI79FfZDFh&yqR{ zOxR}5q_Zii#jr(;T2zgrz#6>wGuUtD7x81|2y@#gUg()fU{X`#xF`Pt@|;gXamNHk z9+S^0X~QJXO?XwI^lEQPsZbkjf{ry!r;5um!#qkIInt#HeIaqw@1kaGCp;3<Dj?y% z@d-i@#ce&xLqepEJ3wVFO~pcv3?G-Wg2$9{Yc!0t5MUGk)a1PKYb2&Gf;zteiY$cy zvJc94Bo@?x!Y0LkgJgwAcDxtuPd3lAfR>6YjiY<(p$X<@=MT3XKSD_CY;g?pD(1DE zoE+wZU>V`zs-O>+P{d1Mkgg0}{H_%03+*uPj|*PXB)BVsi1NDRrf^~#vEXzEpz=gR zBrADJqNMI0Y5Xu@2&b10t%O?D0yo}S46z|GS|TSIB@wWQ9W*p)ROad^&pv^i8hEV2 z0I<&ou?{F&faoXt<m4IV7D>HA(H><wA~VAJ1|Ugdk|tsB>iCcP*AgxQ7nCS*^(Hcw zM#s2FDm>Bw-(TKDOFcA+ctSZ(kjhy9#WWB-V(~%hdlQF1@585+z4Btf1E$r>pelN0 z7ip4YPRX9yI?=%3ei0y>jO0kMicXA3xpE|1J}L}#TX2~pRmx%%9<;n5FwDb>h2>H{ z@zoF|vPXo6at%*%&1Xo@q6DO{0^d@_1@x>^5fF%BHKk_fg-B9k>WgQh8vM54XT_4F zC4Bmr7#m{kE-~Aqj%<?dwP3BSi^$8&|B(>4CwXBN#QU8yuZRl0UZ6JNVuY@sapVhy zYh>pV!$87|(?~NPMM2O`aOMWKi*D_EdKO*cbID}Ox)Wac4Q1mAk68?rq~(^-LpWph z=<4wW*kkBUMIxo$AnKa1R+=qY8SGKUx5NknFQ*L*pqpCjs2krjFh)WBJ98jcmFUwM zFf8i~DQaq)vjHDmKJmIiY>HqZhqzD#B1V_gJSKDU$S#l>akEvy27e_}Tdt}vs9SkY zBHSfcVK@~+a?YM97vc`OGf7f{Gh8+9shCG8?;o~tmBCOsvBG1K4<*GFZlw07x{~1! z9hy-XS$WR_h!gom>a^=3lP&>i@nm>eO|zmrp^sipTh(8Z1ivjKI{|9R0TIPW;3S9B zluFgZ>lXx35)`2JA!fUlpj^Pi548#99EA!>7mkZ82bK;Q#I>)JzJ?>f7s8TCMmBgT z3Dn<T91Q@5@vkIiFNT8pW*sA65)G$Fa|hGb7e}nBW_p<&CV`e<$iO=V*`3LtC<%&c zc2h=#o*lz6kS(UG5ZJLXU1AddZ=+i8uelYqAN?|FnhZw%8T63}QRe$@kq6<tl8nbX zwJXgxE)Um9VMZyOQo)qnX{H9ir>jrZW;K|AzXb6@Y;|$SZ}t-a<f=_t`^28-Mlev! zVjD{{#-HAUw~vVyuqd8xhRPHMxO|VyOxD106VDa6A>h85lr1Va_YW*74Ny~3IJjIk zBmz7S>X<IcQJBQ6ib?_yPCx=F!`=5%Hj1b#zX))OaK|C0s1uHII$)F+p2&mHI5iwG z^I0)jBgpPbR2Vm#A+J!z8c0o0Q|rW%N=8EHRlgSwqgVp>_Amk{WgKdHH9XD9o4k2w zaPp%3S;<wn>&UNqB?Dqgv?+Zh5#s0-3!{GYHB`>q7^9rXu>qSC!I_53zM?fD5p65p z(G(7Y^S9KLu4SZ!M2av@h&=3^iGw_TvpTG^0uq;3nPe03KEqj<V($6op~GZ;06>q_ zrKn>t7tMnuR^$g@9>7txOXf~Mvt?qbg7n_%l%KnXvPq$a;eb#lukdOK)K`86@+HLN zs=!=En(^WDz|mQxNa7wL6yin@BSqYps)w`eyp<Fd&m=y9BbgZZ$i+PDQNo5eVlirp zFi~(r1#PV)C`u2>E?Ww9zR8{6o#@RnrJFo(i`);q(wXG#@EeeP`PUI1<#HoskaRDL zfPk0tz*H%bGCbX=I8=cGI_4Uw51SaCQvobyhQxAF9f-$2Kwb<|7<air0V{$tM!&Ry z4us;13xtA?a!j?3jiFo4W2_h<Hus6zR+^cV9{5eQ;oBWkPK;*jh#b;~sdM-A5R2>C z(?Pevhh3-{jFO>5JcGY;3An6aRRkUc2c_4vk)%Y@B33h-B>vLh+ybG;_ae)pkOJKw z=!Z^}9h{J}Eo9;g5NSi4^*RR;QY7|#m5LlWuP`PCZwu*0V6o7O$oK<9albe<SE(V9 z(5Wh6gvR9NVk0Tb38duhxRbAuzCl#rTpm%tsb#OAvC`V}$Evv87m+fM>}Y{Fk>iN> z02!=2C7Q!_$!>eOnj-!JTc+tE^Ky_R)$>F-D7+J<Kge=GkBndkXM3kH%-%2ZzA9V{ zRJ&e|1O+v7SNu>ZTDV;zW<&}E8Z8G}s&f!~91&EZ0k>W9=66jHAs1l|3ZmV(@yxLC zHe_oT7n#pn0Pr2cZ_x)v&ACck&o7*2_WD?52AC}pTW4=nKv7)p!^N$*u+7zsOar2z zT7j-nkMI;Y$9dvFMVX`~^Q)c3)og2nNF;k<Oo1<~IA-u=6nUapmL7vnL;gVtdQvWb z7j(Wj`KWyfN1|SudnR{;2MEZHH`EKHh-`R7INz-l#Nsmpyvf=WEQ{!e)c3#;u%va5 z+T8;2&jbI=*8@DLV>?nCsgIIuNA#y^Q&1|V%E;)|1VctcZjk}kI-LLmn+Z|baVJ`J z8d95BG%{h!SHTrwY0Vk}aUaZvVpFxT5{=|-h@#2>`5_~JT3qqeURK0B9O;^sa;)T# ziA|mqFDM$sbDkVEkRg=vY@ha8f!_<7Q|g%T<ZWhNSAh|4fV)YjO3X5=!5=b;gG6<z zQOl7{fr?m%ukQ$=98icF#>eE@W=nnLcGwFF#qW5aUncmFO>k*(N7lyESsOS+{fDL@ zL$uw<u_K_ch;FuOMUEK7ZwE9M%Xpc-$1l;5=k4%_Xssdunr=X@Y9Q1D-P|F3NTff0 z7>);-B;lSh0_sNbR4oSlV??<Pj91F~hCFYyjxmKcDk=<Or?$5DA)ULDK}nyApqRc= za7*1#$BC=ZD)U{#{JrQ?`=*OI4*{Rc0DE(eSqhO3iq#lBUmQE&pd`(ULr_8ZXEEgF zaff0Z4=`3Oh}Li98eYeVprnDszs+W1c##jx;njL9)&vCcN?~EwjR$sbF8Q|c=>A{@ zQX#5|DZr-~)sj;<^)m6#W*aoR#WE$qJC*E=o_>#HS}0*A?s{tejIcf+BPHcICj5xD z#I;S7luYQ+w~HA&TJh5$uPt-pymyiSVSK3LKX{u0JLReQM=T*p;bK+mv7jzT^}IbN zvsP+a&Pnm*uf9V($1);_sbJ~}i6?sZI`V(YXJqWM6NL3)?RdA5AzQ`e2l%Dn=D9P$ zQj$YtB5zO?1gSx`(=G%m@dJSF5kFT#9hw#LD7%+Xu!1o04g&1M2pSPP$c#x_F^3H& zCYS)o5MDV$OnmTNh-e8i<d0rq!#R3Vo`MSs^su5ph-W%0eywtmID*V@-O0u+bDn5Y zmF-gM^<Nb))6;NFW$D7O!o!vmNo<7PVWt4^8&#zI(TEIcbEkKHhf<gsRS<oj;8naP z-m%hHK827i-<dK7K0o9C@pS(&Uf*|q;J@Di1~3pXu00S^Jm3N6F182bEME7xFeV{} z_(#&JZPv991_NfV8RA6jT^Y$WGX`Q@;s!(3z~RN`R3}wBbqz+#1{H<DvAy;J9p#_K z2v_N%JE&ACD>ORAC<N~De0>I2jn{^m?~l*t^M3t!KA*4WE67r^?9{$}GdMnY9@UXj zSa@FUpcSDz93rYP$4QAoIRM*=W5uovNXrI6JtNnn{s<9gk|6k*xs%wmi<t`h`}-_^ z{^c^lpwaWE`hvQRMzv=$&gaE<M)&81CbTH(Eb$Ac^X%e0+)qRX8Br8V-do<tqYjw< zkZrR*dQLJ`U9KPy;l?3dx3u>#^(Z?N;<JHZd?ppTHn8Vx4;~(L5cX*FCwm{PXBWvU zf6k3|vkx`b(#UxzLR%0pc;JDDC*KOZR2+xjOfb4JAZ<8xcaME)a(^zQSoR73qTwst z_z(FCaW7~v2(AE4FBLJlgW@7S-NPw*jZaAYn1zy)^9&1w8Sc|~P^oms<1$h;!**!Q zvHSLgGxC&aQ2J+e+o9FDmpQu&lW`v{j7QXLbzKppbuOVwIF7{3+dgLYIV^`Sy{NYt zid@&@(9eOOQBowjx!AE3g$U{*iE2i*JYo!Cg+)ZU8yJq5e~l?stEs%-XvVNZlQ)C- z;LqHTB;oqZ`42beq>wZE^;91LG9}^G<wtTge7yEW;ala99OqkV#ft2!b+?IC)BxyG zz~awt&#s%E=Dq%LH8V3P*uQDdFep{Wb9|7Xn<f<zrMn^p`u$WXwhlo+R2?@x1?nzd zK{~wGWypG$R+EAEfB<@O)vqj?N~nvlIU!~DtT+0wFuFEb^oJ{+X&vl3ht$bfINfTe zmBu^@<5M9*$@l5>d-Ouko|Tu@{qp*Mucv4&VekGKpV+<ObkPmIk!~~?>C*!PYnKcQ z7_=1MN9k07IpRG=I^*B)N=m!npmV`_z&W-Qefw|`z$*=iDI$DGlsqqE!>TdyL?>SX ziSi?2Mn4T0H|}C4%oM|Iqwl;^NTlI@?f!;IJJqid$${CEXeji$lgpE|47U}O$MYcv ztZlMj`>SGJOZAbsviaDt54PG*5F+K!nLmjH{|GA*?rg7KStNzs{6a@=sIx`}sIdN! z-lR1!u%x$R1Eck>ztB<xg|GdqhvpQ#R9KWerkv*bnTKQWsSbxHlRo#V^e?aKUedeQ zaI$4tW{O{V6h?NR(9(VNoqOnt5MXzA_}4segNBsZl4Dt-hf;RwOfpI*DSC(=pIubD z3SgF-VwzdXI&vUxSY4rig~id2l`sdl8>9!A{^QmBEX`|sthRkW&PyEMB;ABwhNBTS zOxnBiHMFO3t5KlFK)WAftLYdH-?LxBe(2Th!=CGz!;wp@In}KIS>;00Q}UO8Ys<W; zj4+QUeY%wI+qdRP6_S*QV_9Hv{d=iHLAr-bLmZe&Mg~CY{c$bWiw1NPl;dX)a^mCF z)V)CNjdF4^?={M^Lm!|1QBD+uu6(Texy_vANAbvNebLyx2<&O0C?d~=W?ehhxHVpj zaa_oqm@OXJqmHLn4&a*jm?psg9+5_;MH}UbN@z2j>{*Ng4=(UL?PnG*qzC&0!uj2v zBQw$SJp$v4u{M8Fz#<W8h7&y^3fIY{-0bw(CfPXVkUns{=LQsZsR4lVX0O84P%Yu( zz*zVli}paO1RL6}0@z}UWY{1Y9}!89`%#{t8v}cSLOPV@q?zgZmXuleR&7q?Jx!@C zMI>nWexhCJ9-SludUPzc%*f43m{G6JACc5L3{D?Dd!L5Gb<zofWgtB@rz%-!c3imD zyi%>Je!Zx}!kNi4WwP!iQz_*AP%{h5=0=?njes}zXarUrjg((3&oF`i`WQmZN`?fm zwDQ^9)Ob53od-!N{0(iIs#{$rhNuxJA%?h$62v$$Uz5RGlwYZPg1%{cg7=7uZoM>! z6<KR_%PmZ^QYoSjiy4ujLd?~4h+d+197PR0cB-$s;m>|2Wd#I%$)*sRx~CF&;JZW) z(IT0mfd;<){&9#I?eNU3Av=g=%L&WH4f2_1_lGMI(>>w1rs(s`2ZLfvRn2+-^vmsJ zX{W}%7ny@AY=4KwQa3I4woIpy9h&JYH;UZ$_LAM(heetUs#||54p{;7v)5%z;|vO) zXOY(WH~mv@N-MQ041T>k>i{t&;=nh;AvcxMr{8{e#++&Glrt#GjyCAu>@|hSj<&XQ z@7|+>k6Pdrh$#?pt`YQ8pqjY@rlm)ahG&JkUt5JOEUU+;k|M)*o^WA#Z`zhY7{;gH zb`oCd7#{o@qljgRmJo=;48<<5V}pBu>>*>Xc4VEne`@&dlo0$pwkjc)wrXfh1G0mZ z$NyXVXUnMTKDJNDlQ8<+hI_8QuqhqzUh!MCt8JN$#DuB6d+geGmnwW(PSciqv^#`e z>hrUT<*af_kdLML)w};jQ<KKx6}7_k|M&?W;<l-w&Lqx+W|OfLN?^C1u}_=rT^$(T zcj>RINsoL$kYbs%eCW|XnKNt3)VcFomYa$r;dc})rKs=CK(#vsP$gobj?RQ<j)F0k z9H9VdZ;faU2<=wjBeV>sUpClAbTr#w)S&=a$3$V{I}6%n>j1fi?-#$;g~v8ax1T%! z?sH_t*ozqjzP#e)Jb-yi^UJ4J>!ejRFfNz*#s)o<YcPXNg-1soB9qALOB{4CoMb#3 z5fTJ*1mk$|&whQovlaBX=jx{ehp+sSEH?U=q~OR!poz0RRsw$-S)B*2dhF#jmv<=# zv}W?LCy0vhwb!C^$rEuc9i+=WsL~n`8m@njdhXk&`qk?x$L7<0p0o%OCZ^)df<GvO z0AJgVwCt^%)Km}6L2E8X?{4utZx7>S?D2d&JxF3r;_dF@XyK>bHjyg!q>kXT5n{I( zy~P38J^>Zfn)f;f_FU<2NOvE*(Ik~3S#2L8Mu8>Quv&!$$brOB%efeHz%pS@W1h}& zaL&=!-zOCNWme{-yE8SkKTGVtyIRCv50Gr}YTxl$Lc~4L`>lp&&SS62>T;6WG)g`} zCzmGJ1AhPFrAN>kZhDxtSqB+QH4YxZtvucNo4?IMWU(=_Fq1+4sES4gfGTl?H+zP} z>5T09BPD`Esg@1f&k3=W1%ri)1q3X^DYsU4p;U;2g4oA#iaI&ME|qx`jFVNTiL&wU zP?2aP8Xm{Ia^d%`^U4MuGp}>rltppOB109XIX(ISoyZy|3gT{FVnK8Px`x{Ii5>}K zVKy%1!9m^$5|Q@`WM+yt&wq0c)raZTyj;Mhrn#;#T>dB09vP9B4B;c2eBR@vsn24X zcy0+NaNZR86NzhIy=g4kE68;!xS*rqWb!9!zS+q`FtjQP<Ux@9=vkWoB~+J&RxKum z-|95$N{<&4W&`Cw{zP3L5ib~3S>5sYCz<e!i?rHU<~gnk2*ii&-Ozg9;v>&hiYL7T z<Vm~;4btkt?xc50Z&fM~zH{GBGb1Pc_Fiaca#^sF#w;$;ZQJ6<TTPX%rS4raW$3@I z@-`-KU9F1EB;Wy^j=k>AUVH<Tjc5MqKKBBZ1x`1qY&S$3Yy{tv%X!55-L)Gp?RpS( zj8(q!Hzu^Wu`f#^Ct+Uek@1l`F#F?z*#|5WLHLk1M{xE$lj?kArUnBWQj=-N9=QP0 zII`w?8im%yWtgFp?5Ef_s=;kqUS%-pgA?aZ9|q4b`x|DCsg%{}%49I=O+1@S$i@N4 zpw6{p$J%2ZSV9@<=55M_JhE)`H5SRw=6=dO5_zrWoWQe?`#Ja)@%paEe9U5n*_w(= z{1&Oi7#D`pSUtOyO1%*g_YMV^)x0@-qLVTUoN(e%kah1uPP+jmF`ovqa@jrhxhe>d z@p78nGn)jyacSMxbxr3_e-yMV5^h-Z=r2!fLDs<Pj6Pd48N_I;By1@?h$1c}B1#nY zY06UYiFCf_hA^2Z-@x5kg1`&*zNO1uw=m7ZZ6C91;~7f<Z{j9T&W$lACep8rN(8mY zM{W*XRsICIHO0kjMaD*J1!+4pai4PV`ZHSj+v7v08ikao0a|9IuP)4o`!<q<+52Rd z%D9>e>Ez0l9Tmn#7pel=`^azcctnX)r{_b~pub|lmN>>G3&(Zm)f=T%+%n-4{ipG% z_d5-&T{!W<ogY2LV<ICY0!rF~jzVL<E%DWAk7I4FkwXE)1KZZHd+J}F2LVq!C@J=0 z#cw#I8uWxaltlnVUB6thvMiPh(|6%J5bsB6;qyDu@TK}cIwQ-;TIB<i?d%5il#D91 zj;#B%CMjS$B6*3SP#bPfv<q0Ld-X<I_NdC73kBovEJltX+0F*KKH(`xIM2HR$+Gi& zLDhG#9mBbbka6mQm4wfd&}s!k=Y{3>I^GF-_6APO4`o?tfj>2egCTdMzLr5q39hJ~ z_CQ)lF5apUNz08-Y81<xtf9imbJ0%1i?jqGFy27L-BBHPdD6akDSym)Ejnw^lEe6o zEPf000UQnL)o-0aRqQvvl@}_!C*4MrK0vfQbJ=HiI^#y)1$HFA^Oe-JO<1jupblQM zOt^iPyE~x0UyjcAPvM&8LFjjsgKLPOfTMB)KQ6OSAa0(AQpj8lXev3OnXOpbpY>%` z^#&||(?tP*C}C1$1B{w3paIkp@mK6_%6J@6D)^lJSDIQ~U3K%H`!uI!NyhX{an|ZH zd^XpDRk5;7^_5+RHR}tIOMt7(8PQI2fAV^H`av$Q8~F5xpMIOun7HE@UNLd4P30Ug zLWy>Wh*4#M_cEr_Xc=N0?vNvrzE9pH=>|SNxzZ?9U>}>R)8fyxAqmW&3TpDy9~3Ow zrA!nk5kf_39p47+PJH92{$Kp87n-*4RZ{sp!Wge)yGrfrp7SCx0ImY6R@h|BYU}MQ z`}|Zo1PPecovjSyIT?j{E}E!|*S|6qQ+Z?2Y#U;3xaTAQm1!%TDL6E_M(dBPDgyk- zc{aEj8{M7yp%uKQqt7tWSn_hVy<Ci1WuRj?B=Qbp?xZ6|HGZ%RIVe^Q$e?=E=kdj{ zHn8(b&yq71B9+n%%x3OHsy?9EzmPfL!(HF7qj8XOZG%XzxnI36Lg_LzF@=Oo-3jza zkhSN-T}nKH8Ht$JNvA>}ziCtF4t{lSh^#9+rU%`XV!oJ>d-=NhiuB>isL(=`P7ATY z7HvwGFU~P)Kx?sm(Y$#;r6;?8yLnI7$cgjtfZ0<#52MR&{xdYRhdlQ{JslLJ%484k zeQMm6Pa5YwB68j;mg2DH6;rj&;mao-KR;~|wfRuns6xq*vQ}((#NY@m9BpG1bp(PR z2I@<=)vU2$1*))4vb<ah78!ivpQK%qaBgg<%tH30qHAVK>kw_BHIX`a+FsvW3=qDJ za7K!;kb%><C)%w%)^5!M>GZpNHvXY#>P27%<`ToujVs+EE`||d32{$LRTBA|;Yf3c z7Ds|9nW$PMi<u`?NbK`ttK{EJNA4yzm>nI}XcmJ&HIYO|$q<7$x?Sc3M;EKw0`U<| zXmfgB-$<0=gYP=O{YzoABCf><CvQa}*NTtS;O*eYA9Q}_`ET*hOZ)Zt|B$IYEs&O; zh(yv?B~OP0*Frz4&r-nl?zV4?yX6;c4qE#UR5VM=IZ1=kO;6&ShGjQ=)I^@AXci3( zwyj{zvkB6l>H)6op6OPce~_47`!ZYH+*iwbUN#U0#5jHjZZ*o+J3#MT-)F~>jP)a7 zUT65UYtsK+5fI)Awjk_^4m276Od^VSt7Kd-GzH^iGuRUW3HYqDHrx5$$qT9j)!ogn zCGdSG5#58G*s3|m5abN5F%8<BHtB8w!6TfwKKjAsVX^q*Y|S2f*F>}{p$K#Q5M@+M z`TBC-9ZW0d_?P0|#w)_4i8SJOt-1c+IV<hRyhSpCLCM8icPU8EeseYl2NCu+f13hk z9B#S#GcnHokdw(X9j3EjH6zyp(NyGnsaAENh=bHLgEnbl(<gRRm*NtjoM*<Xl*FI{ zpa^~^_2Vbt@X*g`R)Zp^=U@~Nj9(dQRsADw_|5-4%9S)B;$?x`6vk;JvJov9q{P6Y zwHS<w^N~)_GFF2(*{U=0x{@l!%!-uXZRZ)bv6X%s?#iD})W+6@#()z>2okVb)>zsO z*Oa*-N&EDl1Cd){oswmLq#E&ud%ocXwj%C|@OjUamJ!Fi=!A~et7g=L@-6lhmzQHl znHo$hFU$z;xKNOkS)_uKPs2Cqp)Y77Oqj3jp3skBRT_RTx?uB~(yy}85|H<ekKNeP z<Hi5t{PtN)?K^;&#wN-!(bVTcsj*toHD<ctj5JmQkPy5ggFRp38?(_ehcm3uHC&8w zm{DKwnQj)6n%Gp|sEajPg-N<cWJ4H=Awwn^4BwXS^0ui;D*fel57Nc{8+WE2yxz4h zYEhy!sP8A*$pAf^?M^vN&J<bDnPsX-I_034LCBg)X#2#JN@C~zJYH@ioMQ5I-lD~w z`J_e*Rm=BoU19P@p~1rDBn9qX{8OtF#xeMJF+2zdG@-v9^{TC^{?7R2+wY(Lw?BXD z{y?npObv~H7R~r2vGg}jDgu3w)t6Rn&a$+z7sKaHlpU#+4L9cVKXPF?6dREA;suoj zREyCkVua{65LEdqta|>&pAU@aTqAtW<gJBFepfVnCo+P|Itzy!NDw}{ya!uL%-ImR zRR;505DTn8$z__;7G^-EQOC?EC}_o{3&vFfQSH0d^-0bSCySZPal)rveq>5K6(=l< z?}x{rAn=E<6J6g53Ah-Kh_sqJJ@ddd6gg7y`ug`I@F5-x;u^8uq7yAe&5<3S{aQc_ z!ZI(DQBfjzQpdrxmICTp7x=XI;NGSCeJP_%OM-`7KD6<kh+_=zeS~v6DtJmU*7Kxu zRVvl867WJQ2$}ERC}OZsNXqCz)$bg7GPUhwM^vR7h(y;ZgTJy#AYYlYk>s`scW{QM zB~q<XpRxY))1E^mpt`fWa=`L0M>7_P*5``I$HOub7A0Ut%}?ml@T2UVubCUH8aAa_ zv@<D%9mg15jlGz0&34#7(OflrTTpJzE2{%R10TuX$aEKtg6b6htMffE_$cva7VVV` zCs;wCYODcKfE%Sj%-n=Z^lyglkB*&M>+-r(Vocwlmnkk2V2%`H0bZ|A=D|LMNH(e8 z^^tmJoMi>BBMa%h3Y{U0@}NPq7sFUHu?Agg>D8EDTk={ke2`u}*1NA0dO~X=dqE(` z%%WX&eKRWbYVU@2=9*=rp{LR#duP@r<*Q_RPlw=uGu!ki`m{AKq<7C%NLltl=}8^H z<}wEy%gL`)T#MRJfi>Vsup12l6_szSP#?%%Amcjv6RjHY4z*8I8o4H};pb>i1G)vV zDr^?Q1er>34m^`0Ba;*A8j(M$AdTz`n`BanwD}{orc(?jeDzihj;C?jpeBi5L<u>D zRT|Zohn2%F$gW&n3E9=*x-e~%kwZoobQDQfQti(PaSUqgvR*CQMLYwYQI+ec>+0Y2 z%sz7fdFOOl=8KeB@OffFk&+#<&vNVOq@y{i4Xrjp63Uq{>;AZe$sy5_Of8)JH@;9f zr>(4Kb9eR~z4qOxZD<JOc4m0S=6#p~zK+hAXlwcMyDzQyQ4qPUhx%AvToh@+n-;ay zY?OUj(8_rBg)BI(SXx3H;y&xjUndoKE2G#czVQYlwHXyzb1%}{c3$DHcjwNDCK}!p zO`1cv_1NIA=Da`6rlg=kReF#9BonhQuSSAfWFfWh-|4pwZclyuvty#e=$gP{l(@aI zy~_@EhCMsnRk9G(l9A4(B@sv#4B1TDX5O-6jexLLy%<|-iv?4RC(Dgj1`vUV&Ejn^ zOrfHS=_-1JAB|C{%$DRZ(DqV&9f%a^IG?$v=-B9T%+wpgSl_a9yvCmIl7KuFQ9iLo zh%Pr$zXCy0Zhyn4)_a9^(JF?G(ZTgmLi5$$^S3EkP9M=?M~+x7JTD{Qq8$#WPuJ#( z#N8I_?Vm0?*pF7F6d-V^NDl~S^#dYQL|~T&QS!A@z+OO;jOL(lQDCDhxb_(?ZnUL! zyl9L<h53rr@}wuB^UW*109{JJNiTBcu^83lxTPbw@#pD6Si~($M;K|!(u?VPBaY3a zN#(-f5Xlq#tJWtL>?Ty{Sm@spK~pGijCR8CY`VQ*lS&3Sq!&yBvL_fB=n8_wyUzsu zz~O+nwV^QA{V||^Ye{yAG}pj<=HRb%9Nr)F7l-#NkAYd&ZQNm*U2D_gn~Oul8pVdD z#EK8|9EVfhD^b)pd}Gik$am;Vc}U@7s4@1(RhdTD;+}o2tkOmz^Y1-&zeNmD|KR1E zfNY*L+aV{CVeW$dbK*#pCms37gf%aSj}+xhVT1T5Aw@u|SSD0@K!F8!2z@)vvqLpp z14#^%^--T-3<?JbFfp<$Omv!(5@(0P#8Omr5sjj-R2D09O&L0wQGdQfs%vkpy0Yc; zwfteV1F#%8z2O00-!An?_<Wa!gK*mdW(C85f&p*>VG5;MV*2!Ij3MuvvS+~>^QJmi z&ChY)L@S(+yZg&TA^+ZXNp71ui|<eS@Rjw=;(5h@hpjl5h%vmGw&40#qHq$`j>MJO zJs@5(1Bzl_YalyhfP7`o@($1o@@}vYSB>{)zgE3dA$>p`EgNXynw{zDvPD;4o=S}X zM<ZQpx)vER1b{bkf31R9oSJwmUBW)Mwp2}W)nVI>8^M+Eoz=^g3xiSxOir;M=d7n4 zZ#wjv!A!0U(3Dh?t|Mt&VNku4AW-<3mqCfVg2neutnN^OyN7`|y$P|7x91XpMamIM zUGv1HRSU9~uVL?L<&WQgWCuOXVGotT=cgM9n@RGtqkkEl?FiHJ1_w;+&W}MwWE@dH z+9X@f&u_9@i-ZoFmvYJ{M5RptU*A|2ZzTfXOG|5{JdQGi95l)3jVQ)R^xoJwLC&xW zvFjWB)9?B0+s}=?JhwHBk*1pe(>$tgWH)*qd?`F?-t!M(7y|MuqfhE?CFZI8O+>-5 zm2*i_)_$2%XAqgaaQy~jb*Pciz;Hs6)frxj^^v9+UpTEiw!dD!U26=wAX7q7*wucH z0CKZqu<XFcccJ<-<acQMt0r^ZcsfxG3Axf6@9+60Mr*8hKSqFd51(Nd@1;qO?HSTs z?&)LiEHd<%>5nO(2($7tIqku>Vke1%XR%15qZ;C|>^6oN62Fs1L6iq-klUwrG`1s0 zvfYfOLQRZFMjml9&_?M%_ZM93-@M=Hk!zP}cE;0fHNQpCQR=9@0*AFgD1UGAod<{h z;_nw+UHR(G!GQwqNL(^$hI(8=D;>xyriBj4p_{86hkZg+0Aor{ZwkX=0)cGOq=Ak- z|Dme9D18)HwQ$H{Fqq6|7l)B6tCA5gA`$F))FBFiM?q|)m0Leq7K>%M!;;nGTpI4M z7g_(7s*0od8izRFHlT4$oFIfZqF5wM=hp-@93ce(wd-vlp|2%D)<CPIrXjp5jU$zk ziX*>gw_E$_r*)C<#f07bW=B}<u?>J}2<<Seasb3LdSEBpy=|{YU%Y9tTRA;-S5xwd zq-$IAc-tt$sm*r?zN$EKi+@@x2OMaXl}9xZKcdw}je1L@SzvWQ{y1{sy+t#DK|f;N zL>)9hinICkmff?c_+47_)K-W|&_}6H3lZ)GhT$)cW?I_or>H-q_-rd%Lw&Shaw=Q> zh!)X_<6`YPx1W)(C%(}b6wMU87BjyCi+JjWJXj<2mcb9~WP{=xT~pgc4p3BVpE&XE zYk=#vovg>0js_*c&}D+s>~h33xK}$`pOQ(w=-?|E=xeXOvuWPA*)~N%fY8|<lwV{s z9Bo+K-~iuFK?{@bVg=|;toj4{M%u|`4Fgccx+&miN^C1Y4+O$fbk1g%fd~mb38jzD z^e%F-p*A`+cu<21<vG6fZ!1!p*OK5=={SxkbVQ**Q`$Gxv)@cz8_nygG)7JOs-vk9 zj8|nOQh5LImu*^<6n<3aq{<Kle&`zTM~G(MW!U3oWREhF%q=<fr%J{+gfktnNIlLv z>T^oNkh@$>5549Q(21zg^Aszmy1tba$5GQeZ7fV+htYFLb~k>RRCel5)2u0qGWTdY zBn4G<^`54*WxYRrl$BM6`IwKK832;yEtQlPTN%s$`O2jpdmsB&?-z#MC$XJqjxz1# z=y)fz0u!C5q|8JrE{+^20~28`7K%P6mGJ=u8itFH_Sicc_GYHXk4H{nj9x`zS<YfV z6XmAIPHOf-GgUk#)>OWG`f`)0n);^HoQA_X;S2te)3}gWB;5gqX8ep+sYid(2oX|3 zX6`ePPvE}r@QW2`0&nl$!LLo{Kn!LVE;!Y1U~H_z<ON3e;X(ZFCuY8m-$KH-X`AWl zGbNUqd2Ev!_;mvo!3Hy}Cx!t~SI*{L)eYr3j|^8NLjrkNDc@FplAnIdaPkw_=XXCi z{qmN98>_q(iz?qGbQVeM|G11{ZoF^1Z~VjLjQPuME}Un=*(RJ;(Bi$HeOK9at!5YC zff;Xy{5U0>kf`gFkOO2-aK_$)Tx1l@ohbk>I$_v}i$?uU7z2KBHScCrGTh#1=37*L zeZriLp>Mu#Y;e0FjG1G9k26;rryPa{FH`}aHFDPVO}~*pm|aN;0n(MF5#~?m7i&3D zigyn=S$Ifn9gg0aOdy-t@gPx$rvB4atdMVhMsjqt3{{J8QSaw70W;G#2B-&kAB0}{ z5Tds#=<&40hO}HjD-BypDf<voxxXc8R7xQe&5f3pWwAFyc<^W@e1O)=OBP9G6iRlF z5zBE#LnrQcV}u{i5!H9HgS5gJ22QsH@Bd(L$JCL#{G_7L$lBdfn&*cQ5q5LT$2zi# zKKk1k4}r~j8DFZGE<yAF03)^Ig0)ZN3RiZ04nxidyIXk(7WA$BC;#sxW6v|wOb_+A z`S~(aV^`(LqU3W+gc$UtX7jTHnPbQPtMRHZ&5ne~IGxT+w1u>QgPCI*Tx_Mn;O&@$ z3t6+1?2uk^)zXwC6XG-8i{z@|i?n_XOrr9o+ZO3!X!~7nMdD;>H;GFQWA69w9ty|t z;{=0wl1(juBtLtEYAyw;%tG7~UuvbYHQXJmms$YoR!VXy*ny3-!D`uu_!A5oC9hBH z<TLO4L}fZLaEY(PxS-&zl;Mj8F6f(<S!?Dt4h-}SP5k7pqS{66EOtj|8r@QY#!a&N zk6`#ErvYOLVN|K&s0Rs75;lxl*K3&Y#$ZIc(`nd)Nom7~LpS4T8SFkIG8*AM+1J*Z z`V6yf0TkI3@TdWRg6u0G!mOxNdi>IaDK5390Y7|b^4_B#{9!<8TTd|{G#{nA6voJ$ z`5(E3O=ImyRz1vRr3ukg_$jtwA}n)5N5>du_x3*;Zv@5`nNkFWbW+EdU+Y%OuZb?C z49kCa2gqDe<nE-$3+Q)f%fQ+{uE!*kly(pRRG)lyG1*Cg;LQAq(s^?i`05MKQK&xW zAyJbB$lQ{IPI40O3eVgm0+mt(ryKG4CGmRYEe=de6{7`_CXk|^xN%u76k&7R5T6-} zhQp-@RhS;Eo1lJ~HHW}LNTRF^X3#*cU4q<jeGCvua_ae9)~&~~`j)6O2p%zx3XDbH z%*SC=kcrG>=<FNdun9XaSsJy<rU~Emd@3x3J6T*b3i6AJ-Z9iLsWAu-rfON_uD}D4 zhiivXCOm3dDjMPiZ_u}oJ8x`?MqfF9+}c@B<*e@lWK`stG0OQ%q@g+PyR^>4aHKfY z@V_g)O~h)fFFM)d1_xXBTo7SPe=Nv5(<05Ry3ULqw;8S@VieQdComC_kIGd7%C)2E zOU_<aZqW7kg6Y_5Aa7NFG*A?}*zgR$MHu;kHKV>@@=%Ycv;9l$AtKCC$t*k$fT?IH z{eJ(Fq~4x^8-Fx$=-PMh*uDLK1}48ttdzKIxxs=ZdTCX0jC=!u2DT0=HHpb^e673J z_K0nP%W{kMNb1^Px}!3Y#n2cgj6a-s`Di97I2kgFG48!73JUa<;crVi$5tl0FUt3i zaw}UFUCT2nXI-6iZa_Mh#9hD?siJT%tFsO``eaXhA*(n3wF@%1z_7DSjg(oT87c5e zD){c|*1l`swif|q5j&9B@5l+)9>ym)I~)pll6ph0UHZ;<GNK&Z>t6(P+Wvaf&G^9; zv5(F~#mzsCG9cIiJZkM9hx`#rBYE+dg1Xa#n;akR8Mt_=8)EoV-VCRf>|+~j!ow3a z`6yX8o+k8>*fN2ZL7lQ@rS41C$%m6GtqUZ$*wmQ=pPy_Qa3QBi6`h$3t+oB88-*Kz zJfk{K38pm+j@74`7=eC7qb88iSJDGa_&?A6KZG+|^xE>az%mmW#o$TznRBmsNSI0- zelzbfKYf&vKSwvEVxG6c$y=P6a|J6DoK!l_+!!mh{u_0!!6k1F=&Wf#UL#uh&G{37 zQo}K(H;)=WowHIl;nInXz_Q>#2NPl(<HJ<k5*`)iSs_WT$+oUN6F*XN{Qd%)1OGKM z7iIJ(rq|TLj5$+F#{)+AiB!}Bgkfz?U_cRo%GRPk$3OGxA)aI5B<M13gY_hpL^(7( z2u{mqgJd)VA-@6PS3CE%sLUmJ%}^k;x`?UOqD%5MUfoW!Lp_sGd;mto%ERTzfx5l4 zik#Kx)O(#1S6{xi7iT*zEKSltw3awE@KTWjnQEC339@5|d`gZ`5d_>y%~rTd6HSAO zHUH)Zie-=q0~J|MkXOCSmy2c-m=&VW3{I}JJ1nJP!xF|<-OES@^tm+Tc3t*GjH*mL zrz<nKUjJdYi%Lcvkj><}zoeRIvc{VwHQ7(o3W0T9rotY&-M^%(e4l!yTzOSUI-;`R z0|4~r;Udt3oP9mdR$V4<2|*FWwolak)i0zLV=TsJikrwrV~cczK|2Ta02*4jdvs85 zaUkuyPvGlpNjAyr!`Y88b>5QQ5x~XzI94q&2hEmOw;2>ZPKwtA=%q*E+v@7%;3OKX zE{fl>lBT%cb(F(y2n}^t)21gg*uA_YZX-K;*3OElU&LL%$CajV4BNxJdkIieVotPZ z{wYfPYr@q8sVH`RiHtWk^c3ytuX+N84V^#z{`LO|PTupMKD_MR*BZ0loGZTvlYxqq zO<UsH=qea9b`z4%C{~_$M?<KMkB&*dVaST)r^dOQ8Pg_j4{R_QVeh9co8(q8+!-@T zF<)$tQ=$h`)$iBiG!@W7i4Ys(Rtna>GGzG8x5#Z<L1B-tzJAyj3jmq&5}dADQJBA- zxr6e_)iplRZBzo_5}}PCBEf<Kd0)anF0G@#`lN=5spXrEDTL?c-9ce{`bT;ZoR0Cm z(A?9yd3w}_v8Kv_mp1TM7<Chlm3<VXp8O&{h^U!wF>w7u56_)E0I>uPNnjGGXYHRs zJY4Dp4h9l@l?mYM&HvS4`_!{@XMT97P3f6O2cRJkSK<8<Tq79jVE3ARp0s|d0i<CR z%CERX6^?wa>xZ+5_U2c09imYt`PYH8ZY(l6c<-9at2X7?yY}k`;{}r>ZPHlhh>bB^ z$o*r^^hn<}Jic$IA&PAEWmOaGm+yzp>hGM{OnvOI?<7%;`Dbp^;hwP<Hk*+xeuZ6V z*Dk=Pe(SMrmI{|1d3#_6jJGc<6Gl2+ltdNU>j-Ov4b}eVK!*frRmkU~(4}S^PO%$L zDUn;qv)6838kbh&uDigOe!K155I;#|`JnSY&KUeaB#PQ44XKW{{A+}Y5cUlYgp%Es zbsb&Ig&h61Xa_f%dC!saq&u*}1a$A`6`|787Wtws@TQnNWz3d17z*8{!*n(4h<__b zKVHCI9$Uh-jf3vxN%h0{(A4QxsHLFv{95zIPqm;1U_45#O{AOhG(hPpYrj$%yY^#- ztx~>)m56aXmmz|!=y5zT3(2Yeg+yv~b};p6R@eIq)g~tiz$fCC1jcE6)*tG>Cxkv8 zX#Knr?<+F`9ZC4<fdhc56GJ>*>+NovkT~`4>pxSpq`kTEWG;)IC-gx@>`DC2>AlA8 z@k(@QsfJu)PweLrI`jE-N!jC^cCo~w8SDcG!idOyaoSO06C9al$2S>=6soh-Y;gkm ze$>LBrqfp3Mw`aNC4EJ}SzwdLhcBi#*G4Kh8v07_t+oF!1-Ih`RMs%KgQYOaqbBU9 zx#D^`-nN1fa;#&Z8S$sf-Yy78CJSU1m~GNSS_Df*Ij%j?8JY$#@`{+p3$(`VNa@0r zDo!W^`=bLeGi^8Ij-VmUPHruUT`{Tq7yeLj@7LWQW}<{((K?afn#MjEFHzaaCkce5 z5hP+e{i8N6LwL*Q{En~CKV68M{U=jKx~C{_CceAn9Lqdx56OU2WtWZF18kFpaaP56 zd?4%lJa~=sm@Om+=5UC3;11rensATiE)-?0s%gm!f(x#=_I{SH*_aw=ziEUNh}htt z<N8EjZdg)^ScQwwy8>ZV#c?|n`d&MK`X|@EOROl49@#SX-W+I5oI;Qs2~;r)*aON1 zo<R7&JTTyOR+4E_>SOBy_*~c65GdLGLc|1zEw~J)x{5#Sn?Nz_N~q|z>z^qKs~U9v zI#$F`I)gL_cL3feUOIW<4ePr5)CRJ}>gBx|!xJr)Y5lgvqHysb*HSLGLjJVTDb+~? zD|0L;IRQjpZy5RXv-^5(9KZ018qg)HH~z%b8<eR6uc9>=J_lh79dihEl6LVOF10Cr zLI!FS&}=RmodMPcU{Z+Di|Q`l_42OUyVt}0W<+)Ip@1QPE09)gh^r??F#ZYJ3g56x z#!|AM4?LdZB4b_~C6qF&S|tppi<G7oB}V^F>XPmT46cG;3~BJDY|}Is1hLy+Ws<f6 zcCgk;bvLNkXR|0raXf9~ko&g%9W^N=EK|>?e&E8-7F8Sp($#HWn=Zj{))KVhcB)uw zP0`h~Y|3K@=CA;vKs3{OK0dhFE`-C(dcORSwyC&fh(=8Vjl^+IiBP4ucsil;0;J_j z&D>ZplN6uY?uOV!9=JfT<!rIY-}*H^fl6E~=lY!TD!m6UP#Lo}#gS)Ti7qOW5Xn4- zrkpC6AXdhF1VQ2cL<Jk5y-Pt2!5L@TD4jRryaS~R^BwA8Jw$*!;7iG2cpMQ!77+45 zwl}{ov@RzFru%Po7%v^-)+^+tmPr7t4=J9oB|4`C`l2)Mr2r4}EdXdSY%k7(0JA^b z!oZ%*v#D-f6Babl0mc7~G%ArJ)p7m>i{2XR4bOd>PGXS7K1pYEl1~q;$*f6c7%XN? zgG1+jH*;Ivtbi7pKQXheopJgdVUoLqRODxvPq~3ko+5s4Ye%{=NsQ%)s}@~OKi<N! zov+-|Nj1caDq4SaR`KP>fF0ng@JSg@j0^9b%ldCj$|Zi_j_&H?;1;O|5wo6WkW6Gu z@gxpPCp$(#Y98csvyk$&74-d~MBq}U9~*{V%RSLak+rEOK5(7{G@FSJZ6AJAh0&z! zn!?X~Z^^l2II5@gxu1Reb5pJ<#Yej#+rJWuFm0!5x>#w?s*)<RGOS3dJ#TV(TG-y0 z{V_-((Bu74in*u__qAMuuk#5$*SYtzZ@bzVdAX7;KyC)fowD_ZhcZ8XvSyD_;nW_Y z2tY#dkYoVEpqG23nPim8Xis$*IPiK}YZUcNlW~ee{{<hxmLKQT_d83{?lS-sIt@(n z0TVDj8L=GJ(<0w>khqwZx_`pl4Yr|6l1okYzkFp=Ypg^6kcS;S5Co=KnwZ(nO_wg@ z7$>H=`i>BS?AZlL=OkG1<WU;aVvtnnGj-r;EK>a~y!x}-Y3i+{y5o1p4R>R3;|BL| zL?wDFEd-V6MhFMGdl4g+6Oy`Mt)KYp*Rj9N5&|v<=I4I0Sl<+v4Aa)0kmK1O`>~Q0 z*><0({5VXbJ!~C7W-_=!@q89P8qk-i$WkIxDThFpLDK&AEZ1s|ha9oM%_#0wIdNqI zJX^0xKzdkoos)ToHCY{ZWwhTIRT`A@r!AdQN<TTVQ)GVj`55dT*^!AwF{TmjavCVL zc1CdUf7LffcW&@EqMoY@-<2jtF8`(x97_;89EzL&$P7h*Ij1O#9W$R7-CHhDhx&cj z@w}P~-(ORcTFK_Qm-J?i{fw8P;gQu4YLDam_*5DFa3OU^+O!%!7k4}l+K0c6tAyh; zoVr_7YNYj^Wv8y(tz(rClau@bDM$H(k5B)d{t=9E&;3S6NX>S}@Um2KV;tP>oIU&I z|7wuA8&C&<iP`&+^U}onMhU3DpxR<|=p#@asAUv(57-}Oo|_V%-uXE;kM_5yLKz%q zmGE<<VrQ;T3&Rf0lVQlW!YL$W@7mWYV-5$ig}YB5<npy3s6%b{lNaCAzxvO6k2<&; z&W$ZHDHXz+B^}ZdG4~V%DUb7_Ho`f2taQxPSya7W;HJUZaLxJtJh;B;T(N0rojd(R z0)D2OYottwH7!V?8&J>!TSri$K`^tct;>^2{SmP&H6*N>KBnnDTHS#+Bi?AVy{0KM zmnC`mArao(l)bDP<OZ|a{;Dx&HJyk*<er)jbUl$RNorkv{S3SOj#W|cDhVq%hcW!a z93T>%%Hx89e-e%X!j!1GIPefdMecVJZzsg9I9aHletJprM8tQYKV6I~maJHl3MKDe zpJDw*^s5c<1E83Kr>tsuJs8ePjf^NE)e2q6m%e2!@&L7&V*rxQY`jR(g+jy~+b>P< zqvK(9o}NfXZU9K8=^`g?>-*yw3Vh<)`hHG8?@xKsB$YH;*3+y-!X2%%qcLm0Dnj2P zB7moNG`gvl5rZn^mjc)yxFbqZDv5S7PPff#bxf^#3Ol_DgmNhIjQl&N;WS=dN{xV* zXoCo+QeD+lQK2@vHU(q4hq^SL0Y4x^Q=44->y(M-_tf1QcZU5OAFR>v_Y>Vov`sE5 zozEFK6OGGGhDgs+tIS2G9f%|hYgR?zDg=%xlN0T>IYy}vpJZ}ofq9KBZ8U+__c{Tk zNnUC!oJIOmgnGWm%pD4K*E}o0jl{(f<U)k4{y9i{*v;T~^y?mK!>*pU`?7lgzB5jO zANkm7@~SH{0h5gF`OCv!Rg8HWTWl^J`tiy4<~*+UzI<Uy%Z*(i*iz`jgm@&Wyr&um zN(lqz_n?STi__95XH;Lk9Xqny(&{cgcWe_0U^hQB=l$)|tI?oX$d*US_#|eQsy39L zy*$Y{h!<kIeu(I2ARITva%eVx`=L)*@|<)hwn2z?vy@(OG@^o0gV^l=)qLHPOf2(N zl{p5x+tA*r|0d|%d|SBd^=80J_ueRlA-Yf8A&P9nxEH3wQ)W)+&r-h5k$y(LvRYka zb@Ae1avgFnY41$bbhm{zAyhNs^*}re`;5<}u=b*c-&7=fKl^nmH-SE$caq;e26Ta* z#+J;fm8|Y3sNCi%jPlHjfz9@P_7g3vcsZz#qn46(E_|Y;{E0k3F*1DZVYa*kSBf#| z)xN)s!0QJ*y1}cqPrOPVTs?&$#Akc(b4fmFNj$QItcLT|ff%nMj`>3(9V?#H+(zI= z$Cfp5Zr+W1n5N}lLXe-i{*`*GpiTvDl(fn_`Twzx%Fx9H11)_NA{RMf&d=5ZQ7IGu zKe4{5J|6C`DvmUa-(cg<2cOy|dTD{fk!|^-6+1$~$<Z8{H``Hi$atP{(p<>FDbtGu zCwJTCH?mjP6EbAab9TF0B;tv5yNbfX$$LsI=bowHSTUR)kb-s}S>eymr9R4_2^z@k z`K;Y%cS;uvj?AF8s!0MP+E$ZJjZJMR2hho1?@QsEwx8%-4dNq}NOA2S=RDf3n>c9d zZr3r^%jP@WR?lpB*IiZMN8*_upssIh0h4a7{7p%;^8%L+-Dd)mMlOw~!;@`1`<-b^ zZcOu=Eoql7C=(sP*MKt-F$#2Xk!CuVp%6$w8!<sY2frzOzw+6GHO{5N!ELBHjVikG z^=B8u-I7wi!tbdPVgN5SR1lZ4b+Q1u5O?*9d>OYIf{RinH-=SOiic#;6rZX4MBJjc zF%gxMEc^m*Fx#+xs2y(ALF$T|M>?{iZu|OcK~-c8EoD*mO!)f2@iUDAG{`F#%35|( z^(i&JhR;46q8deKWSU&gmmM{XDtz*-i43Wa1uhiG<=q-mb`kcctp91$7102vXmVz1 zIxq_9$ZB6Ow1lJ~oU5&e5&Wei@jvH}lIczDnh)fP#h)CS<1mpPS)%q#zI$8#QODOO z_3pmPn;^JKMuAhL7v?I>w48}Yfd}jpqUrSe=_yjBr9r7XRhG+K7$VcZc>P}FmO&g} z(Ys&IxtdCdlu_oPtj{}Zq2{ip@~cdh4p@xuy<MQJ#O=dQY6K3q>Yk{I==o$^LxIs- z`J!}f8E_0v=c4-6#vd><LFw%-oqQTdyw(b{op72ct5QtFOGOP_7m7+Uekh@wT#lKM zQmvUYc3-EWyJ!CH|2lYR`|Frf(9ZtPs@4Zm&`c>HGDH@A<Z(<}S-058tC8_R9PM?6 zB2okgCCs`0z$I6|K6g(XqIMliyHKk^9*dUyR4|yC*0o8E)*9hZrx?o<r8%Elo3TjO z;W9=NmzrNjxpupQP$2sagUTaW9+B2R{e@d%^;FM|e}^2@U1tQC()O5vCp}QhyhsKV zHk>V&mY^QSoYMNr_P2bl9$2=_l9JSICj@D|Z_q5W7Bwx9ia45s!(B|Fr(lUP6EfI} z0$O}r)~|~|T4#MzGMkTMoIMrZ+logm;f4IWnT?bHK~S?HPz_BTQlkP#4ovJ{Vv+LX z9L(kGK<pmHhBEpL&yWs$iz*<Th1#&Nu(Yx_zZfvSG3V08xiOgP`k^@RZF?Q3%bU2z z8=2=+RgJNH8ZVa$|FiTUfhMMlbbHe<eNl*N>io&u@|i0Ek?_X`Qb4(~QTfgD2t;Hr zuk{2S6h(}lGUc$)EO>}MnkBbT`K`-Xs>?PLO9vh^g99$BcBLw^!CysjfaB+(5%i1W zuJOk&Fy31CJZqF`aa-(&wWeFvAp;}@WMOBE3=5+nCtbtq{~=>5GyBgS57(`k>^t;v zX)u2w1zLF%^?$fo$zzh>T{rct_U#s*kVOu8`Wux{3e8ubYLyt2%qfcbiKu_qzkeK( z0V6Lk#Ww)wq_9!yzfbZsZX;@WUIY3G0JZ)?;NK*p(2JM>v|>mf7mLwN8P)=v5gL_C z5qy!<Qj^<Qnur(SnfUnzZgMi_aeIUr5@Kd>Vn({ffI*4-g~H&AYA=B!7b;pX^LwH> zouIG47X|8D0DaK)5cZ?I6wz8~-E)*%X`iw{i|97^$_xcXQ7rfdW?8@tC{kH)`G^E@ zyI$)#x-+$D_T!zQ$pp~pisMB{0c?~6;L2EcuA0}=;heQ&v%x7t2G3*aLXe^5pphN; zk_JN}%l4(?xDd|^K)-USfv((vsD*#K*?rH*c@xV?<u~nU?VRNS$<V6Tn}Z$R5)Fv& z9%H9mqtkzGq~m+zsl!!?TBGq2WUgR!!yNS~)ISu?SspG4(cD*30R+|(W*-GH$5A+< z9mg*7fQCE9>2l<-xKs*=urN_eHG+y#EMWX-SW;#MtC7!|A;csoA2Q*jmKziY?y4M+ ziEIKsvY)Dqym+Xs1IQi~ASWSjiTbKT&hLlu_iEYoOf8iW=h@wB?H4d4QnVeA=`Ukh zsLJ?mo<4{Az?%0|lzNmTh)R<Ab9f7<p-moyaYx8wh@_;x;Q?BSYKvn#pE{=Dj%s?g zT*Zo+^BQX5Ea1F$$D9q*yLWo*hT1<KT=sHIX0|<wtBtTVQEu#>HT$G5s~HS+ZAy9T z&M^hgAS0>j*>k5y!g9Uv94~jPihrztRe=j5Vi2W^I|P%_gawN!xoPh~@sr{+vs&4b z=<~*0B4xt5Q2_T-dWf%|GDB;~tCl1=$Lgasmwv;15CM?861GX(D>rqtrcTX=N?9Ih z#Ng{$QV2yE{QjkNi*NjIVdtKZtul?B6%f9id?7KWVNMHh!2Hu#nh{twO>J<A@-GoJ zJh{iG9?cTlh~Qu9*b(^>I+l-)$W;7A6}M?a_H1!F5+RF0jLrzB7hc;i*;xmGR(E|V zGBQvd%pi)RX8t)|+0G3MuX^TJIl`G<33YaQ-=YEF{tRy>G_W^_?fuMHfxB{>CJZUH zZX;cAePc9A$*FSZI?^dYs`HyWAc7F}9X78Q+0SPh>I&q+iFDdneBD&4&fid=2UHAG zy+~Lu<jSp4^WlV=Es<084RLl<?~gvo;JtC<O#c;{T(9$#)g{7Lw!U^fK}b9af6!>( z6keylp^AwvyV+rUk2MQXYv2*t=l^2h#(&X9;o4NS=(L#8s$kuP%-i@6_U-xal-WUL zTv;ait&W}>n`T?!xO#TS-k$csE0Z@ZKHxZ(Qnrf6bm0Wi@k7dS3D^PnP@!o%D~G6{ z{CQ+Si80O4hweo*ix`#_z_YSgHl;n4*9nQ@Lj7gr`NKW2js3X$#+}LfsY+x6bv1p; zgcBncWiGh7u;40Vwm};hSb>36t907*tf#A3jjdn1k_g#W@Gar)=T9WC_$)Dvfxk4* z%gPG~5mByIs-_^RaFEQgc4J9#Sf&CIQp-N8or9)QTm4V;S9S$o&v0*HXAZZkxy$Ih zVYm@TEhAuqu~0uWJxWi4k1z>UPy>3p+ix^1bG)#d8NUggVnHzXWH!`yHl1w6Umc3% z859O&EgsoFlb>lT)5Con<t%-Hzjac^YG}f=V*r^cih*t#<qKXlt9ETTC@MlPaIgTh z1v*{zF7vz?Kjm|z2g(0%n?5sCDWN;Wh@;xzvL&C@w?vZhDRE?1RM#aA_|2+Jxo9xW zqG;YG5*L~)v1_>h8Twb7&<$>u#xS!kX=i+q;>#h|&EGfxZdJW2#js_CiTpaNulpD& zc`HR^pvQsuJk1!ObuIE|Z<k2dxw_3TniisUdFeCmg3Xdh@)g76Zpnn^A>{e0cuG21 z2;<r>Bg(Ce&yp@*Si!6d>||$HSNf!$_az(&sBwzj0cmfZVWbipdoY(2uPose>|fL% zruS1q37zrER>eqorbiAhYSpF8(Yu$iGC9N(-1J9uKZU<V#p#=m64Jiq+K^^0>wR-@ z@ek*o`2!8pj%XI|4lQou+na#*Jlcwb3H|tbp1<2?y?W*GOB7K=-iI(WaV$-dv^>We z&AHfS9<o^vo8{CtG8-;X`fQ`0g2cNwhqmA20MCaOjc!DUS<iW0>`JE_6C-%b)w|C- zJLpwp5qn(=1c@bV(oX#yEEZXEcZ4Zfkq%oMjU(P97OUq^{|L14p{(Mbc@i($!Y)<@ z&#{YlLyCAkV}>_M43vU%ndL1Dfib0g2#V5nRu9u#wlk#Y1KP1Uzq8MijYpzPZ1hhz z{@DOyrLPR+8vYW49%m32iQoO7X1A}N6Fr&kBnyZ8`&M5+d+ts@dELYlQ$MBziq9au z(q%zG!3oHOX5VD}E7^bc*GsdYcM1bmA>UUt{iv!1iCLFWO~gb)WgWw&b+T<bW{I;A z9wDP!PD@7jSdN(T*FQ8WqDaed=~9DUKrq_q4jZE_di?Lb$pTCZuj7rkoVMPgGS2op z(Bn)*u6uLs*ZT>l^*!Ul<6tqa8aRom-xD3Sa7wyShA%ld*^ZPJ4W8^KyT9p%Uy<<A z?jUD&ctod?XIp@DhnlF@FvlEAzI#w6jMq!o2_GcRU|877Yq}z-T-_8|WcmIKj5~wu zPxj>TPiuEqa&6c9uGd3TfwI~ydjQ}R(-upXnMx0BpoT1NOF>iHWzB;!xp_`XP{KgA z7EE=)vib*9A3T2AW{2Do82#|=1|CI5W<6nUrQ(p@Wd(ZMnkb=x5%GO=LmRWzX1sVC zmp8sd51Bi@w9DGH%@3{anCPrK7KMLB$6qtDxM1CIkdl}~pfGTrOf-=?^ulpetdP}* z$&JV%<!pIdl>R3-S)u#X2_xt3j4?otk&XJ5&~n11NB%_ABV-E-Cu;qi4~2Gtr&30p zZAh?cp%wL#HZK$Hz8h^?v(ia-6bEa!+hd$nG7aI9j2Zw*ZK4%Q+YlD%gRM(QU^t(Q zbRu>I^b%_7`m|z#6B&a1CyR|TC<(BV5%e>+a+J2aktZy*89^%Ik9`znJNn$Ty<BaU z@1K=mK?(NpoRMxmJwhLfrNQU(&+>7IMnUruVCY(A>aRvVp1(xbjRgC3Bg+}KXqIT- zK=vh~XmFSeR**+!cdJMjl;_l+nrvi=a`b*1?O9MEg{CC%E0Hu2xnX$(JZ_Rz-M%Z2 z^#`F#gL~xeZ1IRp%vZ~YFV$C?KfGeKh;CU)oNDmIRjiR61?0CJn=UyEItCpFR>f+g zRMlaV3qDM-AY4SZEsQgt1s8i_qcU(VTv#?Us>v9TyrcS^MmyKb0PGC^*#3Fr-AtiR zaq}y=&N#BqYqVp;`mU?*SS%PzeCuVjKQ%8LL_3bSP5G5D{)d5)XBSWGp1*pc13%Fj zttZn)dk{91MAmPK)JM+8F7awFlTy;9MX7lcK%iUiwtKc3JUD$sOz3;|`3)0Po#=%R z+0$N7@3D0~toY5<(!DS{7;eA1{VS?wi0t*rc0D2oV{88Nw_=;2Q1Ic>uVbWR3E>r` z<UyM)C`XhDAg{=KqYX^7pHfjJo#D0{wl>HhWME~N7pqXj$}U?0m+}ORDTN*KxwK2o z89sb<;e$5lTI6Doery)Z>$mr&gdP3(G64`U+iB2+ouBr6T-`&9;KtLZxE#{Hp_-{Q z0Y_djNCVt6Q0zK65JZq)XmD#F6r^I4u<uE~+n-T+Y2!qaD=AFW*v8M`aWUSQk4I=_ ztFV`j_(`Hl?e75^_RQb>V%@UHkMXJ#;D)Sn1Lxo8B&2TypFfc`8fhJ3Ky~T|na4&_ z4Y5|tTcr1xAC&I;W5v)*@*Hj5Q4hR1`gE1)21~QyQAGe`=bwE7Eo=z0uV255^W-39 z@WI9BL^HlLQF+~{${bgH15hszy_tb6W2VotJQvZ3zdCyD;oD97f&Gkz4W2p2@89=A z%_!gdPJL&#!dk;uD}HM+^3okHC1ij6Q>%+WYxPuaX-&X{oSZsqW%rRium44Nu<D|9 zBYGb+CP-nOPFM|WFao`n$XqdF1$Iz2*yK*k)NKU3Rpi9yA$&RJm^78y-NFa^8*^`u zX)|r!C}D2?^U#n{y_Qm@qiktovy@)lVvmCF(>{fEyak7A_@Pp90|K-HRd^3#1~yxS z=4Q10-lmK!H*QEiOawa_hY%AcGYVEkeKnoLP!9$rRbW(3TEIHVTD)b$+EF36OPp$& zM)V+O6H9pFi7QLjXU$1pShEQw4G2z`A;gGg2k#m;5X6NjZG)q^7!sH@;DUXcA)h}E z7gU9t2t`LkNlD6(@fI?K^tV;6YVD*Bti_%<Hu56)7(?i(FO<pO_$p??VyngK@gpnW zh)~2npbKinc_g%{J-51z=+o_WAa>X#J4joKsd3A!M6B`kRdtG8sYK}gk$!l#(<~Dh zkUaUf05ZH~%V4tBy-*#di+rfR@U>t$N`_sbA>d=ahQ}VZmg$}3A(m=}DGubv3~Y~b z<5Q!1O~E;Nq%r(O-Mr?esvO9ha_~HfdWM)nZ=J2WkS>Il6cq-WT2te<C&StW2Daoi z9E-Y)uYu?!6+>>G)N~kea%?dezVh`fnDA-Bdchk?GimfZQ?fTQ(2i`DlU&#<3yBg^ z6%@*yse0b%w69S;_{H!W%3Ek9WK=?RKjiX8C{m53_A(9#@$jkPkmZx7EeJOD8r@W; zu496Vb8}z->|>{Q@`uX)I=cs?wWSsf&=Q<kzWvh4SG!*Iak71n@>S9dGJ5k@K3Mu} z?z5}<FUBs!RQd8Q&+;@>Y4)Bg=X>8Qy$Ai=U%zW%w#~72TB!mvsnh+y@nf&kwioJe zo^9ggb=XXYBxLcfoRb^p2V%bj78Zcda1&D)<7*BuBz(D{EaV@bE3TH9&FlF^>Zh!g zE3eg6YHf;`Crdj)!t1p&+@^#HoO~UGWva>d!LOSEd@=>GW$`(Tx#kgyYB(x3hI4tz zeSIBU=Y)){mtOOXRB$!KHo*hCs^jRjU#tE%l|Vh+n6e#yQuS9gdI-ge{jn)Zg>wBr zh7(2JEp7KN+07Y5%|<Z%((K;d_#=&ZjY7~)X(gEZ4kl4BqrBNERV<%OoHwU+!3JNP zdlsyevy@yndkO;J<(y#s;SUeFZqy6ZEZZk%10|&xwQTC)e)X(o&X-Zee~9Fy<_drp zpfFGJ*jto}a}gAwZ<~rHwHJ!U(^=&Ao)HM*OQt1lA5cG>93R%v^liVxYQzpzU~6An z`&TD1tYfUH!<96OfJytQv}%uD+NR^yT3nc}yD9?Cdr;Yp&q$>q*Tk#+=;4y7hWQ7m zCTwc9VadowidK-*8p)4HNjl=4N8z1qJSi1JyC|#xL|lrVj#Wrtaq<+Sv~;TqI57U` z0bHYuSjBVQdXoP1?e7shzUZ)yQQnYpd2VNfn}&m*w@+(vv8d@_-i(22V-cr?^i!oZ z^6?^AH7e1oFs2lAK!A_6`;zn;L>!Q*g;glMn-h)tPO+fPeiqQ|fOutc(XECb!BPbp zX>{$g)2PMXPe6=JU!^J{r?T7aJ+wSR9o-s2e~r3VYJlXtEdb%|{s2W(?AAm<w-97e zuC_K)J8?_(RNwdy;~KOBb2Vil=Fros2dZzL2j#dLkZACeyE2+BoCJ_b`Up#%g58Hc z#o#b_J;<rn<0?rlWebrnRH?1UTfUBw>+|yFg*0(*PpoJRn9?@+5{eL0j#t)uj>`X4 z3GtI2jmD1h>{g~LWh&kU;}1WQHK~~lOwk`TD>flRCWLiDY{oV6gYrx4J|4d`DX^^x z-X|H=7cdqfZZ?PL8@Yt(D!sVhiRkEzo&vowhcTH}$%F9-#X#<6d;@(2=d2X0C1NyS ziGDnjtruj~^0Q=L5af%En5j}gDi0OR9%FNIfb9Qzu0?L+^2r%_v2h9!$csh}9lHl_ zq%qK)QTwH7lH$14q>0TYjB?CeJH`AxH<QREhKUd_xafq0?Uf%UbA(K~edW-s{^_mV zt#Reb-50ZQDD>#!?2FUVVn;{<BM(9!BwAw+S23@N5bqDtT=G^#_fy_KP2pc(tq~3l z=LaHag<QQs%Y?JTEyASV*vX*tT8<n$arpu|J?rLruklGsF5OUOcA6O@wi?RJCDSO1 zCP<*pY`WX$8U!{+d+H(@x)oTJcJS)6x|Rx@zi_S(c6}2fj0iSj?q1~YMS9TR#r_si zQ%puYEUJnW)k#&)`SJ?|={+M>GV7YdG8$=Kd!h}Ha9(5@lzF<9l3%8@{7xh5Y+e4% zqgK&iE(Br<-E*h+Sa4o-xu^K$Tr@_sCg8Vs4h+ctA<k+(NZKIiJam&HSo*BzeYWw- zWG9$SIwd$uqNE~*bUTACzb~7+eLwdJi$hsZd!}3vI-yBNx6A@UM6t}3EencH(r>T* zDxHCd;FNV_z7x(3S_+u0aW<TjM9Du|z_%ZPC+}UO&r^ZL#(k^7fcN;uI(22tEQ|*| zs<HnI@%`vM*f(_ljY*eIj;COCm16Z<3gE1!;-X@j&@z-i^xWVRjp)p3_W0^z$5Z(? zf}F^yJW~Oyh|aoLsb=hE?M5dRI<pKqCqi~yeeqAI8b(dU?_jpO{P1gocm2En{7;Ct zA0HyUPNw?V?Q@zey+UPuuHp~6fb8dS#|l#6iF*$+QU4-DuUt*fmzg&cSxm+u<yrMs z>|Hp>4+!M9Xg}jdr3G4UcG1TQ9#GNr79X4@^3CZ8b;Gu8^%e8lj4V$Iyb=VLF!U~X z6tR7Dt%8Ji4nHz&b4t^HV>}M>Wap_BurZc~F5`%xBe1II%>PJ&RUP=pSHll)CBjd{ zYzn;I-81IUEg8*r%Tyc07{25b-M$LMdT^srNX;3x7mdZnmlcX~N61W>$OWv$7^1k3 zvb0t=bSn?DZNRUWb|M*rKU#|e`3_x&S~b~1vk<YBCnn0`#&Y#(BAXh0$mx@po>go_ zDHs#EV5^zV(8ttFhqh&Ab-*e7a&;x^r17SE%7xe2B<vON8oVxz1N?TxA`y5FshI)D z*)?9XeUUk&`hj>kMjjwaXuuSEE>5ICfmmaI)h*5g1aWdOkBjNm!<}2&kiisR=j6HT z|F;?NGjcEG-F>PZO4JfTp~ofY<ewzewD?+*jLmn-$V>uFPi$LX$kN6%n!qIYd8sb` z@Z`cLsh^(8UzA156VYf1V4AtJ3Vg8cEW+yS#&)b`rahc&C~<tY-D7A_T0U*`Zrk9o ztO4}tpu_zV>Ubup<dkJ{R_s-a6kP)SNQM@d+*}&>UsX<uZ>?6&@wBqeH?5bk52~u< zjCslJmHK0A5POk4%}>ho<_?c$ySrhvHAAt>7XNT_!cQX_X-$u?_QDj4vn{LG_I7Mz z)-9xq4EUYWHEKd|hbTL1CNY_UcSH!GG)Z}<-k!;!qwA^ocE7xu`-7UNQyD}Frfe8^ zd^wv9AK87p`7N0sy60LHw5<0Zl|#Ce=G4{LL6{GXNX(d%&sIVKuD;`Lt|YWr-fLkJ z-JeUh%1(Or6{}Bur$a)S1scCT8G8&MGMaqjA2RzJe9AAZQxn<41k~Jfe$P`YJ7A?x zi5Pvx+QiGk?Ka&r)x@5GV=Iv^b`UCuBR&0Z$|IFXC~GD&b+<u1#saDcW(ssZ9T{|y zaDsq^n3k6oF8Pxxno%}eXWe|Dn3V#PUef+E)R@K(55TF`rV2D#uA<DxXeBkBKVCI^ z%GGALk08Q1{)Z8<+HIaum{S>dcd~%}Q>SJ{=AmfyD@AP)i1u(E(VkjE!aFQdWh~60 z*z`;J=3TfqpMlZ67<KQ~**DMB{z5a7*X+D-7++1ITDwHBO!+_h%MhG1?4}BD@Q`g= z5m4;tk?Uj(m9;L1aR<h|d%m)fQ3&Bq8E^FNG(0TGHjGPVIJ>Vdmvii_<jWylE4^K< zVyxq$8XnIW*|i6=U*;l-oY7_<N>9-|uw7~imi5w)k+B0#xO+12@BiwjN82M!Bn%T> z$kBMC;htw|BITZZV#{*r9JmOn@W8CUyMxMA6=*G7N@i)fh<ycNtesV-$L|ksiZ`z{ zGQva_n?NeW+vO8!GTY8?5Goi0cxrg?A1j~sJOwoHlF1C(de)*wCk5`P<8<&cnh5UF zroC*^6A!Wu-G%vg?qvJ7eZjm2PBlekR&a}S)K*p09yw4DTy!ezoU(et5G9^Fra;PM z{UHf1Qw6U=;uH)@;1bmx`M9oo-&-T&am_nKs_(78q=vFkNgEeQeTFpJBig>ZGur67 zz-u_6K5{`b;Dw@va^lmEnU&^JlHuE95%PM99S=6ghSFCs3uBE3SgGFCU$G{2*P2uV z>yxuGLjoEG>+yg0kU|tfwwjo`nTjO7PcvD_{L~POB@||*+R-2!IoxJcB=ZECDNU?` z`Uz1i-tUV2?RSjl4=RhaL-vS9S{SV#X5|*apka1BL5`Gxb|A8t%Vx9eO-OkTRMV2g z#Hpa8a(9oK>hbhyw6qq^Yj%}eCO(6YRd=K3ri97J$%NIh(nZWOaCjnYik-<BU1=!p zYE+DN#V0^Xv9>#dnVA}o)4a7c4c5?>NXQ6&xa&1LbGgiABU&>*t~?0Fsh8F8w2$6@ zByzY3fw>@*q#QGPoaq^JvR^Ac%K~x%imlbnNGRF){5bvhYemn)u!^0|U}#~o`C0$t zqzrfwZgW*ea1!l(?ol@|tJ4Hu*#@+HRQsM{=d8XNav@tMZtuSO>CPXwH!M(nkF?G> z7S3F7<=)z}xoau9d+jVJT}GYfvZ^aHC{D4*MLd98=`n#Q+Rfpp{Bc&czNV-rctrh> z5*az~{o;-@qS6q{Q~<ML_|Kf%h-)d-2vTlOVq2jcASH<FQ3jl`m>sQQ)nF3@d-t}T zDDBoE{NVF7^hL9B@dW4gbqmR?99G|{97>=zzi^)v(yQ)K>pr3NRX_z+;BqYn9cBco z5kIxWX}7}9<Fr8sDZ*Vh3}?O7V*VP^D!b|3n;F}haXve-V?xZM^TJT20@*H43T^w@ zPc%P~|L@u<_7;N+?yYN>A}p2g))iC33M_M2$YQ{i@PmQW8A>i6lgwBclg?JT!ho_@ z{93ZahXrEh&VzgJ9j5an*5jn0J+fYK6FZI!{C$W7(6!usM*h`!E)AE=)Gzx8@yI>4 zgnCV(f9Fo>CZ)}FhC`qXf|1Pd?CxT+O-lKY1j;ba+%7c|o@X6(jOy!mcc60u50+n( zZR;P#T!QQUejsGpo=muQ7@c*cfnHhYZe2*0(I}`^YYITG_s@rA9A_vO(Ob`6su}#% zYq1CctAMp?y}=Gq^_k_9b;lthjHq-B1U%6ehMk$&pEfmhio3@qUhlb*jn-XpL6Tb( zaE1o8BXHhn-ID6bsXA?Z#M!(0$Da7`n^O$2w05+AtZ+Os^{?I#v~)6#VwJR2SY_h) z{ONC$Ha{?8whJ=qspdjiq^7^;$j6om25{QlWu(?b+|_|Mn4BtdMV-e|G{VS}cW>!R zVn(v-IOz5ozm#8Q%i5$Y!^3c!ryJMn6M;$~pdfz$1=jxL%^nJ141jW*1R+}hK=sz6 zMFG2)xHM`Bieu(38KYD>GNgS;>|^d#TWqRph=5)l1{V54!ad6=Y+XzIPK@Rnp0SG3 z;)?(uM0gbqY4ZMrp+{+>ADPSVI&p<j>W~k~qi+i61RACCjQDGZ>_XF1ao1U|v<S1w z=!kN&B+ax!=|zZ?k-5^lu80WNvo@DP87@_WZh8=(>SLAIuH?)tEwN)ISH!JPJW!`3 z14Xbfv1T95CC@8k4QV_Z>}noD;Ujg0GuGFE=ESc046Wfuh3>>NlMROnk3je;9`l19 zfI|H3Hrp^yE~Tdoa5s~P+4$l>fU2u~8BmE!Q-l9p9msN594f}oi5*frP$l%YDt~zj z#*=G(5Ggd=Pq8Oa8`<{}rw@IhPiQAL01u@21G~eb&YB>vFyI^MJUT;)hFZIBjn-?e z;<@0+Qop3uENm^0OGLHvGvP9LSH6+B8UhJ2CM(={67h3(pl6sGG`2ID3kizw4q41t ztlgW)`|8bZy?=<X6s6&cy4Cv`s-F;J&G^-Nbha%k58*WPuUYoa^l8n|gPp?<#;3j2 z9e~{Axzb+}h%3ay#tV$vU0Ja9pXRDxae53lsIom@(-x`BCMof=yQhjxzf*Jg7TS&d z?6?g-dZSbxd~(&Fwm-bYzT5eZ+$*{*wwreB>^qvh4f%nCZ6}vGbZ6%HloMln_wJ3- z)nvrznd{G({IhT&1VgrHi=EdVyt&p}c_8G4Ls@q*aO1D+#iao1<^)GmeaLk+ILuAd zTv<x61pU@5T7DPy>U9uHL?5X(x`OY3@3xG+1Mw<e!$`o_LfJB@ZU-7;_FBF=@gr$V zXd2Lrp7k2X=a2geSoUcUiw2ozt|r`>@95K7*Wx9*V$Jc&j#f_^wQQkrATx2IWvs>{ zQm7zU{&ZvFW}tCJ<xA6Z-Nkv!bY5KjZhXGy(|1wD2-z)<xLpC1l4Feg7%n!ja9ly= z;DRzYX<cgV3bH7?+t8&`aAp8P_Y`-b=tE(g5!4D{5eLFd0%L^@&8GBDb5;15ORHpc zf~yW&hC8yTiH8d%SxtGYJz*IXbi5%fGN2KbyAU6ttLO3MT_ru>K)A2RYFy%lS9S`4 zb24Ig)zlV%VhX#c2`+Ep6Dq<R|D`}J76^H#VD$(ygLf9A029oM%=C_2XlS=rb;xV2 zIX`YM@XWry_3QuP|AL$*XlcS$RWe|^5clwp(^u0T;+v2TB2cUGU<!MiB?|>`C#8f2 ze-x05%+*`smuedLmKYQ$RP&udH|-$^(!)tNTQcI6KsZtIw5k)+>mVf`>fIZrLV^0! zzRzZEnm0@Np9jYlwf!k(P9CzgC~_^gj$*PsTQ9vsG`)(y4sa{{Ms8z!CPz-|Xc85} z8)i@f)B<YYbFPZ3dDp~hpUh`&wpSE&o1YVvKx)Cb8i{%~I|ZOulnXJRjsg!m!c8kk zPY_7NnbVA0oW@NTmmgJ@962$8Sn_#7AotGeYc^4F3<tNgH7w^d6Y}Y(wpQ2<BOL8< zpz>m1M5=k-B7Phg>{#vCtUv;H?~WpvQg-iyaPsORDXM}>_Yy)krG87wkh)q^CCX?8 z!n#HXjaaG?^zpfZB)SM(qjoDA#2=KnxcoG96fW(H!D>adDio3~(_rNz1fk16OTxqe zucgI|=&jG#sSN%d6{ev<9V}Ke&Sr{liZzXV*yOM9gGmfknucVZ?2cuj9x68|?0d^@ zddNQeSE02ByMswxF*!F%c@x_ZN^w$30##M{Av-PYLM(g0`Kpr~kuN9f;JMRLWlEIH z?){7vt>Y@HP*wzfqzj<pcsQ^8l~^UgNUOa2RzSJhDRgg^G}d&EE=$$h7rsI;Zt5q| zGJaP9sv3AO%q^`&!5Q%hiWQ8lOq=gW;?5%%j`xLyN6vdtQ9As)4~0WwMmCFgr5o5d zB`r$$dThzfGh~wGh|w0eKVM`OP#}uW&areAst0|<+Bs}ToV<_mJ-{dG9tx&ly5c_m z16J}clK~_-<<|Ahx9{FQX~&k~cn}3l3?o3(H2w0Vcm0wny!YlDJ>xlVSslF3IGTHW z(NrCWvU?#Vw><;D$a%!N`iea_{y*2zCDi{+0<5h!!GE#Sps=48ncO13hMxa=;rcN& zlB`XbhYkgx2Q*Su0<<s{yRSSJ*~}pdd7p`wr=|h~So1jCNy39$OR4Y`XnwmHYW3;4 ztwj+}egE`d$SR33iJgQ|uqOHkNXD~^LD`H*P6!Cs4lq^<cEdFkRKWRhIb&!#aF9y( z1sBrA$(YRWXNuUMT19^q%v3cL_C2dA(%f991{3@R$C}~}yPxr(GGpAb)f~Q5PqE6D zCh?u>p8oQ{mS?(eI6S^8m``WXJKJPHdw^thZt~)mizqA|;)(NS<U*eN1j4Ta6-dvc ze*pdn%O$SkT0Xe!>OyXgQ{nazI`^jAlII$UfL98lkqP;C);lfcw~h|}%Ja%gCghmT zgMZ5`BfvaR{s(7JGtmMZ#E2^*i@KERvB-4Qa{^?_LVB6nV-9!U+Y`94_A%t5TO8E; z#j9U3Z_f$fz+Bh8|4479(hZfb{11PW*Q<o!fz5+~zF^JvOm-`#g*X1|NgDh<Ohnb$ zNbu7~kpAb*H|KbAS%c`tQUuBVIE<2C(aWC%#f2MfXDRK*h9~~{Teti~mh$J%WfFkk zsI7vKYjo<l%t!<>)4Gq3D%@r%hk9E7LF*DJs-P?O7QZ|CIJQ0Am=T<hy<x976Yze> z#x-u%wMK0yEvk8dVE-0qwB<-O<&GdmwG+yD!K%evPH>oXi-B>3yw6#@gz7d^CneAd zFy`ZxDgk;zR&(+C?^PN*NX@dCP{q2U+2<6`z(Q35!geTjZ;bDm$_u19c_K7xT|vRY z;gQ-A)#~quGmB<Zdr!N}xn5_45nl_l!YQ`Z6B2$~M=AaZmHxOkSfpWZG((AV2j*@} z;}8fE`Vm6}$e}yd(!({~Mg3EY=z&WZc4;2~DK&Oz)-6QwAvJ%#K^8E;ZZ+GsIEBO* z@lIbIMwBC?A#F!;+)yd7VFG3RGAt`vo4eKo4R?L}JbY58g+NHJTWBhE+P&E^14*;2 zWG~xh_*cr&XqjqLqPEaOycw9Cnm)IRJWHjR{TJbCB2;65CsU{{>W2JxcQju%6Xr(r zKJgp3CN4c!R*lTFi2>sp!!uP1O?hJ^BFKLbIN&T9(P5i{OUjUfEnFd&CghjKLox{T zdHs8wELOu+eK#jj<E(-HJE<xT@eL@O<ejZT?F`E;`)FuZ_ry74PfTpc0kj7Babi4a z=i+FYV!+g}utUbu#!W29h^Qc<-%;g~6z#h&O3cIdWSo3rss2!Z(zCWF(8}+QXJ1;j z4F2wpDbrKkn2Zb!_{Ps2w2Kz(>4AQKVOh|uuDHg9t#ON97mZT93u9})(P6y$<di~e z3mv&@^p(NkW>BY;QjQfD)*GflL^|&MuWp}w^=CmVYE@m6SHPoT`g9ad9J3CxqJ+?9 zLlI@asoPF_y9eg&HMRZHK=!Agm(!@7`oU}?YQsC({3u&8*g#K}2RjEiePF!J19NPD zbw;;-knDtp^`%QI_H3cj&S3U@W9%Fc_mEwi8+5xoR-O8d@wp7ea($?T<F#<+7`w*d zIsUT@IuwHoL@v?uSo`XWnF6|xt8O=9XbqdchkYv!_xlR49LgG#5FzU`I;V)Q4OFW# z!5sjo=1Lr`n~#)6mj5HW-SrpA*Ts=CvcbVJ5jLtkAt;~Z3=x~iB^YJcT#;Nq{m<Qx z&Tcu6=7*AroMnritk+VdOp8%hS{JkWi>Fc^_O(EQ2fMy?X_o?Q?N>Saghm$4`SvD1 z?|H%!qHNteu}Dr#&28LfeJLDXV*T}L4{MsQm^c0Dp*l;bB9Xfyer!<)9+jA$pr#VN z`lgtXc%;NE2qi~YBOvV24XYh9_u8s}(K+3NP|{W3R}D>Xz=R|aduJ96=L|$B(VaPt zJ8=x;mI+!yO)v+H7KW*@g*qFJQ%-#HEWR)uZ*X44dKLsF$$0LSHuMaYc|16NFjA&* zesvk;q4j-Jm}uDs9?9-D8$ssT#=+b}G4;S52tibC$qZ3JAv`f7c^2NeHwco_A$?Mk zzfYbE6M4THny3P9iVsiGmG9Ih$a84tbNfy&(z~+<|152Ko_`ydL%6aDC(cjXJy*TQ zG&V+s4(JNv3@pWtdtT{i$NqjZRdO;)8m4!B-*~;lZBpO&&Wo-G6=he7%?#<jip`}) zFBu+Csf*JT@s+_$1iwLMHqEJeg_6=VWrIWHtgj`p5zme%q$G|N*#?*`l`d*@?aiPX zHm+|rs6&3`r9`z8VE*wA@Zg0`Qx@%gXaY(SB}@n96XH0%OU+$#HqY;1G#*ze#2ot_ zB}Af0o=4fjt>|Hzmz+zN<x863L#P{>h>q*xsogHlkR~H5D7sMv5nP3UsHvG4l(;=c zWg{@tS1}3g7<&hpkv`=qvIDeI^0^`)8@uYq;<i4)A+pd2e)fGoG-9Z1Tq{KqY-E)D zjVz>mc&_{so{;_u*#vYF@1?@%n4(~#yqpk%F_MN%(x~0eBx9AdAhNzCxWmQ2ee4J0 zprn3b>$}a6ay>Gs$Z>AlzZ6Bfl}YWOE9Q_Qv$0RIFqcb@AQ|QacX?pHP-7ug2!z%9 zDA47^7ZwFX>>A;5%>cza8+pnT3e(P%_RI;jqi25l3Q(%dv~4(#0l+=u4+*>}Pid>n zq1X7#<u<Zg8h>fx?yo?p%_+1j0@n;e_x1zx-}~?lUBiMUz^wEVG^i%p(~l6(#-{B2 zv;}EMFfK{zJWo!wf(79x44>uaHP}(QT_gY_Qge?BTl;D2C}0~$ned>Kevjfb;DeVr zGZ4RZ0WU_>C)Zp$eUO(YQQK@@dItQ05(GPvDumoUlij7|hfSJ7hbzbQpV(p&Cg$pq zovipj;__5yp+d+0=0UGism7JlJzG`eMP%4anucMiFGN>`3pw$cxXG!}myNJ1#J7jx zg>L_Mnw`3ys;p5d@)mEkW$(_3MzjEO=|~DvpnrYnq6gjPET{C;Zrw;+==A+08c3-u zt9e6nbnt8~7>o`PMi}qgeB_3UD6H-BwOO<rD2iWYI)^=&ONrd?958o)%L#pV!-__| z5AE%0KFaV)sHkRVulowJ<UyAO946{(L(>?;rt}r)(zQhM<VxW*x`s&=v2H2KQ68J; z{rI&IX*RMV&yu_Hz`tDqW;}-7{A1_~gKuI3r<oB^s!liERII(>sY<k&tTOvpu|1=B zvY(Az>jVgla5_?0_VKxUeGgSOh^h)z+w+P8VB!De9M+sh!MI4)u?>4)Q}}hH#urC# zgFmE7tYrdbHQdtlE~0X-pDG_SR<L~*Z=@?)I`m*xF`3RR@Zj7DL$TK$Oo-ifd)+z@ zn^q5KJ{Rqn#auPOL37iLhM9Fqsj7v5K4i+>yjrp2S?;HF4U|`|hyf?7V2ni7={DH& z>Z3la%LB+HgJnEiNRPP|{^kTXnQP7}aI&8%WjJX3Fk5CCody|HO3#5FnT@|=p5nP` z;$$a7xrwCUvkv9xvQiVxmyqZRymAVi)_shQ<T~ZDE9;|&0w-`w-@ft4njmH#$&}#l z^u)=%wvb>%(kS^x4Cos|OsSAgDzROS;11X9gGVEHl%gw0L28MF%v&V>;DVB#t(3oD zX>QOWIeI!Zr`tva8#UY}lQ(&2u|cKbfpZ~U7qn1GKTGZmikL!#{);e$OBG=-|4KWR zJAybpn+<V&UZ=(ueU?aJX%d}PY(`Iu`!qw^W@1h!ws?uB;?|dF5>-u2yd!gC9a^_s zvN%DgS;EHsBpvD)-L)8$al7%3Z5r{Y0<W3-(6}kPiTS7Shj=cAW7sl^DJce~n5907 z5|;0UCr-^eMPfk}msDBi0Ow&rbY$F!UcJ)ann;Nm4`^cdZgv<ye|aS0RFuPy!fIt; zFL7txLbUcjuR%SeA9YV(ckmfcKlYmcM|a%Sa|S_R*FTD)K|mm^>b*Ty=fU;KnEBeU zl1m><+^Vz&)1AEV&6OSJrdc|)1JPAkIDvgIW2MG!`^T>DHW$7+(f|NcK24sAfG~N! zx=4&b2X4#AssE;}`OMm&x3qNL^!RJ9RdId5lX7hE_9-|T49g?gY;pNyM5_5X`M~2* z8_eTbkkM))Bk@wysHkYLp~_bxfr*#a89>}JaN*RKOAL#3o|qAuw{3%ZcJVB*?a<)s z@+>_Ef`m^-2k<%r6}e2tl$}m~t&iZs;Hj-_k^`i~UvZAy34Sr30`m9MM(LQe3?$fD zs4b8t^BKAOo)Yr#m5{|ORjgmBD_-4*gjffM+#s_*YXmVqA3<1Z6I1Ccx5TOfjP+>G zaBbXJe%MW+*lt;!w_gH>)^C5^6V0L9#GM%o7cJU)i%tj_a@jkPrV$O1K>hBx4huH6 z=6cssk2qi2-lfJ{G!{V|P2q`X)1%>IRvT*8_V2f7YF#H~8q$aq<=Fk80!?@PxZ;8t zIaLO&PrsoYKkwSaAvZRa##!Z^^k?7f$e48El!E2YVoGUKm<RkVTWKU2)yI<>$0s`I zps)6t1}~V=^Y4gUwDs@CADu(pC`Oj{w*KXXowv*uLcT(Oou14r1OgWdfH?j0yjyns zB<{pm#}lujYI=cUf6tIQYL|+N@<Vw#k$5qJfb|^OIV)FR%}Ux}a4YlSX>Y=3RmMtk zU$o@rZDcHIG0IC2!{WS|YaqJ>iRfj?<2tHKC|QgUTdIJJU)=cDIWcR+BjOhT4BFWg z#+|kl4b8eVoD`ZU|1c43eIox=duma02fO~(TEHSTAW$({71-Xvu_|K=G`sn&4%AX@ zR)swB2MtlQLMR8Yr|BrC<U`R?jXwWl65Zu{iR}+XBs{bQXeM>f-EbsRESS~xJ|w5L zb6az9n}FS<Q`eHXD;<Vyym;}+vm{`nV4<;Rjc%OhD0tlZN2L3t*);Jgg#e@(Bb=p_ zX&Ix9@<0)j=AQ62Y(tog*k(62G0{tBe6}=S>UK|0pep5MH7?^OQz0xOkx0)F5bjo* z0)M?#Lmzjok*NjO2h{j~6AkdQ`Qko`et0Kq*KZCPI;k>vh)`M+Np!5Yh!`p@Z-z?E z;8V7lXMf_-is6LUo3mN1Ea@~nbh$lUR+4yI_GEbS#$I?XB0Q}OGVbzkR_}Y%Er_|; zitwNr<4+lpSFFVb;z|B3T8-e_KeQP>CJ<OJeROtBQf_(IARj~_gjGW=>~ZK4{k77* zKbt2=`Iq0V2>!h%{H4!NLv9%6sHH&@nHacQi7<iC`4>ImN!;s5x*|n?WbV;Px=-cT zUv}>_#{ngG!+MlGFLkmLMZGYSpaEFcDiiBGxhKw4I>_GcbX>8>I72uffu+06oHyNC z$MCir)TqNfJ0t&u)jXXofEEd4<PLIKy~-0=*2i!>CRJ(U?i%(h2GB{IMxVbisiQq~ z|E%7nq{~;HUov#k$}cNp$JP(r_+PZyTS!48ilMUp=-KtmJn&mW^SNoyt^EhyJe>83 zEi5W<6)5u!CQ=wnFG`T*jAfIbGB2TXQI=A`<l!yvEb#Zt_0C$%aUv;_`_<xM_ZPOZ zyX!xlxIG<#+IwA(QLCNXOvOY7n^~*rm)GII5F4S;ySTQR#*kH(<sa*b`;ARz7)l7j zz>Jt~@Vu<;iP}lxxEJ#$#A;Vj>?Sm)_*_@tlc8vdg(bn?Pno~%nL4Wy$!PR@uKKu| z%ZY$6#47mOfrDMcx$!Hr2d^CIBhww-n4>MHjV^rJ(H5R%y-QD@n{epL-#okEfrn7} zV_)+4iN3lmM-<(V6q~Q0EKl;2CU#$Yn4mSD-F9>H))kIw-O3Ty<FQlULBGLBbXiwl z*!WD`dyx7)Ai~7&G63SIeZr9kMR;x&*tko8c8IG?j^^q}u`>q}Gx|JS_v2q51~R6v zD!kU>k55NW^<AE{R~{_CmOw3+Ry{WzAvi@=zCyw!N&(IhwnwaF)snN%XO=wg-8)>9 z3E-BUt+Lq-%rUvVGNO(7I3^T@DLI|lM5KX7yk$@C8nJQbgPkg68+X%WWKolLKpRmf zIcMqK5~lDD74bQ8L-Ij#8_`K(c=lk1bVu!SG=ev6RQYGk#?#Q|IKXx14kO&!L5JWB zo##%!tdiWit97-nb9%Q)tmS)w(JiBZDeB}SEe*NWlm*jQesu84rjbwp8Oc);_Dyk( zP-uR%^W3J+z83$7#cX_A`FcXWI#fE2!MXX7G!8J+f-@qR0HuKQRO|8_Wj|(lx%SqU z&ya=FJC2$vSWV#qR*%vCe4DzK^{dK*u+tZy?q>{byUSbS;mD~d5?T}HOfWun{gt?~ zoxiiQZI{QpY3sloGYFBPB@r>?WRM=6n$<DZC!I=M@0z@_67)fZMP$()OXZp}JGx5< zN3N&ALX#J|;PfNU_6!(;&|4HrSYEreO>jsr6QLOfKu`+^u8e5FIV4hd+|$L_qqPFH zyPP&Ni|CQxLxASlq)_T`(OaGHMYPyf%h%Z#;VyUnc<>9e!J3E8ZMyu@H`!kt)jxms z-PvqR$4xb!Hz#4?_~l)ZCafAFn#%jW*ZKaPE0<#i=U4&S`f#P2^Wz6cKQM##I7BaD zoH9b<aIRXSN$cDml}98B3H<I1fFuh%0@x(I{*H_^O;3Cm?x7%<;s|8@;?f<2Q@(}T zb~a?Xmb+qAPOfaN1PvZJ53A{GZg*{8%twypmd7u*otH1oM8*K+Jq9M4+_4S9cC^fO z8jJNoEImV6Z9zBri+G$Bhf0d{&7e&@fseLiO2U&wk51pZVB7b_^se_>Q)J@#Bev|Y zEpQbAok$s4c#7JrcG7<AJ`1mylGVp!vp*#Jd3W1WE0sA@kG?iz&b%G3y@n~BC?^5r zVj_9v@qU)R#>OrkdjI&r&G4&di&;67@M`?wi4Q*+I)*(sp{+1BLaA{oYlhd(nUD%G znMU)2d^cL$vExBbirLWDn%+69<A=Lu%@!o@3{O1ip@V0oo{5*9_8aqNebkyV!rl4c z<k{U%Uq3u|;2x*0wc~c0#*Q6s77<@i9`*LYD+@1}g5N+Ml=HSD&HEXefO+SR3!*0f zc7};*uUvlEP1F@GsS0ZG-23KE@7&QQyBp-w`+V!%);p%4a7UlNdf%m!Q#baJ!7e|1 z-!Sc{gFcIN!d8i`hmJj{E_nLKEetk{FeHA8w}(bk*WctRtEe_l1iIOE`^@e>qmSLh zNwcDpaY@rIYOY_<L#6>Ej(=C@5*@*S<lmlyREku$k$U~{j-7^|y84>-QJp?@qk~`k zy`5C|PV@MI6lL(1?p+4bIx_T<n(Jiw5r2(AA!YjiYdWLYrt<8J|L?Ui*ThV2f)Z{T z#M~Q9c2qLSwIhW=vIgf)$%ciY?MnmN2ySoysSVp5<t1+EU{9P*P)r-hE+opxBlWdv z6ebcPQZ$%M;w6o#pDKYEX*GEW50zHR`hg-CroUsh`_S3$gy4Jq|DSWd?|kPwubAr> z$48$kldZO9z^8@~Z?s3uo3L7UtT*3Kk=;BVEM{FBE4M}`9x+8IvSydbGXs!{Y>XSu zkjIX0k@j(A4(fd1S(I$OLLItY(~rpZzd`#(K`h+lVVQNrc8Il8x8Tcgnu9Xq?tD%X z<zux$ooyXsDD-%rZ4OxD4FoM^u$iUs<vP1n+D_`^VWD4japIFV3Tvjs(91NK_hAZw z(bv%!{k~EtxwS_+yh~3h6`tL{T9yqHJO75FRNNvCCdoBWf_>!6qOfC=H=m4tGPg0h zkKsa%K1wn}$gd0^g3^$Ib#WhMc0y3Ju<|0ytzA9IZNHJhFKIDEXbe0FoHd5fCQ^MM zm-dt&;qHs0ApJf|LC3*Txnv9tClaI=2e2e-C4Y3#Mc<#|GtyU^E7yrd;~|<OVkeTQ z|0NJm47RX}+u+eiI^l>VIFlS?xZ7DeHW5qIwDEdBy5RaaJuSGEi{;Tqj&}?Uznan1 z5VNz^V$fHqX(a;(w0I!XsVRr}|Hf6)faOg0ILbL#<T8)7r;zaabd8Zlv4QFU(Y!w~ zA4JtGJ^ket_SaQMyu^N|m;rc*eHSrcpJ=+ERiZfnx53R!o&Tu%y|7WzF+op?g4bi< zx9QFz(*;RixrSx{VS~2H#<u73y%|cS0hV2%c{p9-({1f)*xG}|BA`i1@Te+U^w~>; zL+|)IsevJ=PM16Yj7ZvK9#ls2Eh+Z+lF3~hc_Ekoa3!B^cY;<*u_>6%61}9Y5N+2q zkc;f`4giUxcTJ{%BLyQ)8)S2!A#PI|jT({D#Y6cCQY<)ErYw;FNZ6g<q`QW^-SugE zG98MNQ3e^~0%AnTD%75E0R4&UCE8U1>N+uP&ylD_v{keYp*ygOa<XEfq*3eT04Dgh zogf*)_31Mag{1)p-$%kST38zpm^~t*^mW_y{}e$`Q%03!``bmL-;FD=$=%dqBzJ4E zH!&r?n<Y<n@=}#(x^$F2JMO5Rm3*u|x+s)a@*55R+F)q$CRxNcx0g9k20i&FOJP$c zMzCCMW?~gBy302ZFib{WaENU128U3!gk7na7^jo|4$xfeb~r6CZWRN|<GmJQw{DDk zdX>N6+UGwyX#sbEKIdI6<a%<kAobZTwTrjYz<JQdA9#(Bg~#|5UDLu{!)VNpHSe6} z@VpZoTGbV3*1f8vXe@4IG$~I+JSlo{Wx0mK$<EWYwYk1j;*~bHJ_?jInVE;3<V+zE zPrT1IakTSeo#5k2JH@eWW|CF}iVnF8QkBA&Xp;hB+YP8;K-BEY-5l$2xId4`AART= zQYjRMQ1QSXlQHa`f!P;7_cAxd8hwtDA3{<PGm=JFt`Xjss;=^B!EM8?9)^F9P#WBQ zaGHTR&0}{VJ`EGBV0^~i2<66_9as5;Kz1xfLfDyLpu~AdVXFAuQ{U|&4fb2a+$>VY z{IE>L&P=NaDg_O{^yjntCmwiElruSQx=p>nR={|Q#(E!;peXiSgzqG6i}ozgmU;G# z6@?nACq-<W+$3rCmaCWYXeIgVUDHLMt9-5BlZ3f6`QmV4ey;(Y)y$C_XIV^4FIq(v zYT-x?Ek0sc#~Lza#-Cw1&I%rt@F(|aX{bAFq<P)KbfLIUpjXprI0FHE)~ZiD^0RBz zxW&`Uzs`~)i#<Rg-UD+Snn@&B!L>ZG`;hF_!HMfrsXj7$CpRO6oTLXA&?wkzm3%q8 zz?bRzILX09ib30>K}QBc0kf1oE)x`2u>+;HgRiSgk#!Q&h>7P+AQv7%fflY**kL(U zVTwN+s|>@Fi&1|#sJoRYzxyJ0k|`Eib5|ERFLtn$$i!w@hIrVK7N6>YYH2-1C&lAk zD|7}ykA@Om!1V;-mwW>EHp(A}`*3!a{10NO9AwJPA8{+|iT!|hJYgR7z4^PjBhheV zd(Y15jU$`_tK1~<f9>HH_dX1BieTxKn5&6-=Nyp0OH390g~hACB&X=`Sy4a|#Pb|n z#;zGL`n;%uDjupPx8vD+cry==l$V}S^+u<Q{AxsFH2ns}h&q~IE;C}nqmQT0Y+dk2 zT3xERWtsV^VrZ&csq<E=8l4zx52K0;Sgh|^u@Ukcs<qryg0a96Y%5zkljh{>uvVfM zGQ#8t9;4lr`oI0~Fr>wXtvH0T9Tz3vE#<fa77!V<(Gl8_Q9A_|Bl;I%25a(UTD*`s zdUY@-lj|)-yDV<5(>c}zrOHhnuvcWak5Q@7q~|#D`+`P`IFU=G<obMF0Ct2Nx-?n% zPTB2X?0jK3D7|11;QD&=F@j?diB<Q>!J!2g9w_ouFb_ks3i8NS4hdvCn=|=8LMf3> z$7mXjuXWEIp;%-z<2j*{n*^TLi`#Q+50eJO-hA(%BP*CG4CWQHb&I`|^!-PQZ|ZU? z#SO~w$Cy0+@WzqcgEHbpRmY<PB&*j@b?_2+A*Y4ga%JN{ER#M{Vn)LkTQ8dOd?+4v zZOL#$BM_RHbyqvKm(Moi%CHr$t5r$lu0B1d1*k(@HlNE%#(-ToF?nRIDHLH~S18mt zWLO~N8c9y0P=qHALx!<C1^|lw8h)=)ag>n!mc-w%Hp1F9OQA#1r5nT!*}=<jLK<=X zM5D4O(@!@Jkcc~aRtGP0RXAB<X8=_H5t5ikQ@7oLr=k2hnl{>G78wO<U2D}mpQ*|# z4Jhs*(7~ns<fX)JjU1SJuxiPe>**dT5yTmSiTrUoG6Kp3CZ!@7%#-8ds!x@+PTz*H zOa?WunSn1LrZtnE=JwwrxXLaSP7m|I7aCcX#Ss}W_{B8vhoebjh%S{y^PVrKN+F4E zMWz{Ktuq@C&ngdfAV;k@IHb&PG;rSxx)VW^w80o-5>2;qU>v5EgRVqoVQ`a)SQN4g zu7W?<-AJ@Fl#{Bp$ihjGDsW`xDvQiHRY*>Lwswh#LUl2K_agi?!48$gd0pm^A*fRk zJ8W*nQ?TzjGtOfH>ZR@~+{Id8(}r=crAWSn>&LZKDOyPDu&M|_L#8*#Fk`xfVsw?) z3d|<Uru$bdp?#sNg3Xo)^WU%aDhs$9(%+ulj37|cO27yHnzmqR_Qfe90+0&WN%X-? zEIF{2&w^4>y}I?k`{!P_BxTPVE#MR&Op5LE#&e%DCSK}^84+Fr>2kpy3^Ly~F{P8E zWZm9_B?%`9>NJr{_q2{q^op!QI$;190;m|DbXzbt*qPp3|1rAu5EFXBO^DXfe<{x< z&K7-=cP2@T$kl8@Af;s;2{`kJN63&1qr=bfzVM`{RpJZfL$Cc<t{W<R%9zc#G+?r@ z#2z94N#c5=?&6OBiJr8cznMaG0GVdqS*F}^`=Fz!Zl=u2CpNywtjX%_5K`}Q>b!{n zV#z93fp=|OY-w$gbt8T)dJ>%*pnWN;t!$FKD30G!CPPZrdZe4g_ay>J)ApXvCdNJ{ zXEVJ-f}#YV`7Iy&7%6CH#M2`o?wZUTz1&yYrX7S1lxB{Rn}F=5*)!1qKI^yPp>__) zIGelus<9+pjb_|}_yxCnA%!sqqPey~g&ZVP*#cj0nUzzz6NXRP>F67D7F-fy<q?y9 zti~pj0MEJ5nAe1%V6s8KbKk&OE?N7~NW{)-nx6lVA=N=ghN|Ey@t){F-9l6H`|{{5 zGn4){8kIVU&FwYKGi@i7LOnz`J)7>_J{Pe&yI*$S-^-`3L_1j0cv-M?VD?2+qvFs& zl3;;gqez(B+43V+b#)i%R9y0a3VoqzoDjIHVx^zuIaPjwGRG-A8FWPXoj7_(vRX}B zMlqGlpyez-wWunb4KXpnBTzkE`SsSZe!sBZT={w$`Qua)1GnP@(_<~=(HMhy#|)0x zaN&LYOPPsk!}Fp7`_Y6-W55XW&#p-k+LIs;A#Kme#H$`r%maQl;bOxj#XhI1>nn~m z1jR+F!B$3eeA1M=y(`w^0lS=RQoPn)$rMsuG#g`u=txm)2baG#395<f5*=ZBNJB<T zbtJS%Mcm<KVlTU!b>f_B6hRweiA9PEx%6t~Mja4GLuWW5>TNO&O$lKR!AS-|ucc^> zQwF_jxctfMfEYzYg)WQo%7pdG$KVlLz*R1Z7fyx$8qAoh*b{VAJ3OB$B?dI6B3rxS znIMm54@bmc%;(2ao%?j?0Aomz7t}Y3&GJrB&!-g`ThJP`sz&Q8AM-NPu?&e2h2V7T zr(bx2F=Ve=&7TJmG+h>oWPTyAq4Kq6(loMyRQ?kxA5(-5JpIbogQ6NmM$9-6?{X31 zM`5r7ON*Kj2K`!#i$(x%!<L{;=Y(psU87Y$T&}aj)#RO6<|^>_8`CB$YPO2_<sac3 z&v+%#WyqYPqQ4n(GbT!BGTSx09-}ySNyp)+Eb1erKJg||TGZyA0DU4S<XwjYJ)}Ef zP4UU)I}E{a5pS(J{;5Mnwo}hM8~$uACK{E!)DFNT#1MrI4@$1~e!r5b@a;V*44xKD zkKFd90<-Z2wNavcEQ<DsfAF!C9DRBc)OXFQ(}>r)xR+ueL4tygSmC)-XjD}yuiy|% z8R}kNjRVSM77BTp_}etvAhU><8Ac_I$}LI}M1zJ1-{8?X;ir2>C$x^B&4%wJLif1Q z5uo;8++{d4%CvDwc8=)nWG$d*^&!(c;ROm)3j1skSk1)PM`WM^Z(@eYnL@)bx!*H1 zA0QmCg_>xEnyX1v1=RBb!zT89OnO<0T4)skZ_6PD9^q$nzDax$xw~9dIXC1>pkmIn z-4b77IAF2kigt)lvg@Qd)91z!H5^$;cbgxseDYYlD{2~BQH6r|GQF_Y%}k27D-Ae= zJWtOf|ABgt3bbZr2-hPsZBk3}VQS57%FiW+c=CWsy3bvIE=8i4aEKf$Ck31Q*7t%> ziG)N2s5$OPlz7d+Uc{(k$<wBJa5-jul&z@exC5Qt_iu_aV}y7%LW|&FznZ<?nmWXT zj;T7r{al_ikVE2<)HNgOjFZW-5qoXv+&lk-eFKI}ewviILA}Nxr;y8g{RW5NAz=n9 zODcPTJdg;`_~X6owaKQxEnn*6$Pr!4#>TC5*eO?s4kj%Xfays=OGycr?xZrg7pwg1 zJ@cnulptlZqNZdsiI@{*$9~mA3T<aFQ#QqGn&Fs=ulA``T={hgC_8x_`jS$%JzHds zXQTv=e6esGF*oKvKwkx~GESvc^zmLmlEB!g-?28;FUnz|aIjRN`O-mH%8jvG1vIt1 z`ZP54`o@dzw&OLF^ZVaH8C<_X@DyQWW?FF?Q2m8=x=1LS_@B{#M=*VFZ;9mhEYd^t z5uQKYtP!}$x8${a1EmJNAA#$w<4>AOV#!t?=#z9>SYPQcL$IE*BUGno`GuT3X$u04 zt_5!JH&CB!ajlc|AZsixn<Q!9%Ep2X1B#=kK3cp_xE`=%EV(DUyh@_PGW5mI4XSFO z<)+00d$vkWZss-D2$Lm?9GA8{wMzL%&|1%(+}L?2&lp7<A7txUPHC`~k1#4rTmXBR zv>V3rl)x`%i1!d_r1_ddH5OGW`R0FM%@MXjaTMl(n7xVV>BXyDr-PwZv$8%2ezo~4 zA=xgYdq<X2=RXfoPsu75S%)q{GCl<~Q+H+EfBWCLX;J++lnRtgUDdyb>gN8~g}bqV z*((ify6Dk7#)4@^UHZe%7J!Fn`A70;8|h194=C{he)Ne8NWX)#`y-dy8TDv&<+>o` zK_qaRmyrHz#1a&YO5A>+&VmpNFiR5O67`OlMsXx*58>P<Fy@uXNjRPo#Xbm<pEB|> z)(0ODD>&$D(9(3Q@(IHXF`?mJT!d#%;k-EcLY6bprv!sy^30|nBJpjic%()GDv7JB zDx)P!iR)+?=-q}0zQ8qvdXheZ)+ro;-Z{HR0l+IC@Jc&N7KCb$xJG-QIb;$u)pH$% zq<5c|Cc}exZ3sPO1w0TB1-(jjtTk;NgGz<cJPWx?_@KHea^c}?RBFMUymC)IH7cmg zu8g+nLBD=y6*Iw1jQgs|>*`4*Rmma>l7wsGa}vjmE4N8!5p+i$;g7hJ%`*f-Y5|(F zyVATXxg9Ki(s0}o;|L9&40Q>3awrc#QD`GkkV?6UQeJQdOVVK08|`7N?{KOVS0V|& z;vEa?c9=yoe0CGX8c$G`Tq?a$uowXsri{M{8W5%oTYcay0?><5(3?=#(xAkwhSvu0 zb!F^V{>{_ot>wupF~0}_rLngc5FJzca9%s53q;^Z@&MRYpG8Qu^Hn~5(392~M}%Sr zq(v|De)@+FcYqR?^7x!!{WI{TYY!)+7?SmxvsV~UtEpXlel-HWQxsHJVkIgJQzwWC zbwc=+RxwUDEm;B;q{=a7oUY<SA+Ld|<4`gqON$`}G|*<2NPgaMrgk@q;aiC}3}xCx zQvk@4%zz$Sk*NJU21*D&67@(TUXVc8Df>MzmL2psBS1Se^P-e4D6d^Kvh?kb@ryXK z=sYFE)TYRqv+0j{+Z0FZ97I}i#EHSn5l#V(Y(|Ven7?w1sMo6~6}Oj-7K!Bi^xNP5 ze|8cL(0vnV`ubV3m$;w@Xh>WSxy>0U$&A=4(TyLeqb;7fN7|F`XOWszd~|ua*t-3x zN&tg{HI~E5jBh{ttIL1<;-uh8lSC?&R1NUr=)&1%VCJ!a7S<>8MZYl|c8qtH7)g^2 z5y~skc$nN@vZi-IZWK-+#z;AD|A{s(koHB}+Gqo3bopzINZBU|uW}NidPak-)Qopm z*Urh+b?E}V626x+#qqZhIPqP|(QxnV;zx2Z>SU=L_?c#LX5bG49JzO&doa<|2gEQw zEzx$GsD|<o7tD0~P)Dwpgcy-2l*!#L9Hq!?V|T;QpZrrkjSwKa8@<|O4^!0kdD|(5 zB4?X*?lT<;n58IB;s8%a3iCWluWGacp&=Ob`Ci(fnob-Flq}H&I<SSi84w<l4u&MY zPMxaG#33E3$rWQyx>GHIZ%hj4E@?ZhQqbcE%MJ&{n_)v2R5%dwvE^n25*01%{8kAO zYN(?IPh}(pRdsl0koE;P!Eoefo5cc*Bk~_PB_xitAgTv)G)Q<m%aoTk-cTh)c5Vvo z4CXI62Omp;b`mw#r#?ZJ=Y)QJwO<NR2NFeMb?rm&?_@?0l@`o*J!nvBCKTWN!6}Kp zpmlp#9+fZWSWAHJxfH=V#qx2nSN!sx#E5)sz}lpzZ|dNPDt)f~Bq6>xj-+a4BIXh) zt7N6l(R!e@AkN0z+_FMEu!p}fsi)rV;wGToQ>3a5UN}{FuU|O9v&B;!X;BQ0vv-N+ zeqQ5+orcP6+IkhQP(5ey3E4izS1je^cunk}I3sHNgbd_{o#&Z*NL;o)ha_neMJc}! z0qf2+2Hf^?onU`}^k~2J;Xp_^IXvn(<J@~7jHpyk5^#9S;y6-57U2|yX5kXz@YaTJ z&|k`*A8vJ<SNr27IZw4~)!CiVoLV_L$T5*IfIU3e6q)XyzY3XFk)1CxE_qDa)UnJm zAL0o93{b9Q6lM>x*48286M1yhAs0dRIWff()&CFTE%Zc{I9oi^E;6ZR4<Vl!Ig}(Q zLbah~kT6Su5agZHTZ?PfcrYWKLj$2SgB5bYHtfRs;AOnf_C`G3@h<KlI?!0?#`Wx8 zWk3z!+>|(~`ESReiNDX82zA-Lg02koC)y{OcoV1?mmHOtc~y_g^20S%!Yi*hyP3zJ z=*{l#lJdY#7P@gtc;F@M>ykln$AvSAn~!1D;m*Ysh9Wk^H6e4*mg2@7h*&|JU%ieN zwnJ}SYyh&-mX>$fP6rQ(0DK&9L=mUDWM)bx6w;lb<a#cjpYJu$j!6o|5J=9&B`<L_ zU<1fz&;qFY>GwnrfDCeovgK)rKrLxj>VeV5+1>PkYXn=G@J<&lL!<9<gfKP@925aU z4fPfoW=1ALEP(oS3U?s`MvtFkI0#^T1kjX3!6Pj5P~jw>LN{0^J5FSv^v$RtT!;6A z1uW6GrpgchMPpWN=UUA}6%95Al;?SPn&!`YoHM>>-6c!xNeRcGaZ6_9d0FW(t<mz+ zR2+>oBM*viT@c#It%+{I=ICrxv$rxCq!tAQ@Yf>f*v(r=5=5Z|d=BLCloFd5PQa@M zIDq#Wh41f^W;nfePU0#`JTpTzQf-Tqs%X|hc!MsVK=EX#K%3D~;z;IhpWr#Ar-|*Z zg-HlhNZUTjr&@422i!j*hi<9}M?fAs3Pqg3_K2Z1I_8v%X8?mLNc?AdEaG>N2Z+E| zowbLQ8h}PQ5ft6jR9C62H7f^v25hGwm5cnk_d`1?!(`BTt!U5*;)7g({UD@KXtdCt zmm@lRWv17^bSh{1c`d(wsd0cqO6Z18rocm>B_rZe6hg=c?S(}=yzoMMJ;!VKnlE8R zm5?T`*u+_qCoQR3w`}SK<q?m3ygH%>jbdUd#+^>m%Z~l@XRH@S>xF=lDi)cM9D~GB zMt!7KkoF3hN<>U7ut^-{3{fms51;=C`2lE5PU#P#?>%kEVg+ITrHjoGChVmx!l8!c z3R)tnqTi$U%$v0C0IghMhKWCux3xkm59S0>LiLik%~m@~)ZMW5J0n6Mvd~XVrV3Lr zny*lzylvrNpqIEXRAEHm`YQeyr=_qMqJdr8P|g6wKa>XB35v3YLn>G5KrY~hJURUq zxlKI5DB9|Kdvy^v@fwv|f)kpPTs%i2*4JQVAyNj1A~eJ}A!sH~5IdM`{hYIYPidUq z%EgXCmuNHy@$vBouv&aEhQl`(V{Rs1xyV-72djLrz~pX|sJgs*RzwW<F%s);VS}Xy zs*IsAYqUlEhaz}Rrp;@5XH85L5bd+-OxxNsIuWb1!L^RZUhW$Zc;|G^&?g~|QN_2R zd}W33gVot1WD&|!(RGsSYeSawN@d0u>aXxAZh4RCs8Cf=YLD5xf~ByiNAk4~a%=2Y zjJwd-my>@10K&UtE(+#YN+g-e!)iB4<EL9r+a^oxx!a33MO^)IA79QA4x(r|Ui{AB z>@IuQ0pjc<!@+dHD25$ik>R}kkoa<H>jdPG^b=$;THO@}$*4Z4Oc&77Ls}Qs&q6my zldO~THcG!zaRIn*f`Tq%8qE#D8;Vbb#hKW5%X>s27UA7e874t{3_oF2a2#;7L=6Sh go7bYxe=`2_A3yk;i9dcjqWI6r6KDQn!SlcPKVxgQc>n+a literal 0 HcmV?d00001 diff --git a/docs/reviews/richtlinien-gap-report.md b/docs/reviews/richtlinien-gap-report.md new file mode 100644 index 0000000..eb7fcda --- /dev/null +++ b/docs/reviews/richtlinien-gap-report.md @@ -0,0 +1,323 @@ +# GAP-Report Runde 2 (strenger Re-Sweep): Richtlinien & Verfahrensanweisungen — ISMS-Vorlagenpaket v2 + +| Angabe | Wert | +|--------|------| +| Prüfgegenstand | `seed/isms-vorlagenpaket-v2/` (Source of Truth; **nicht** der Spiegel unter `.next/standalone/…`) | +| Standard | VDA ISA 2027 (Information Security) / ISO 27001:2022 / NIS2-Kontext | +| Umfang | 15 Richtlinien (L00, R01–R14), 13 Verfahrensanweisungen (VA-01–VA-13), Baseline, Nachweisregister, `mapping.json` (316 Anforderungen) | +| Prüfraster (streng) | **WAS · WIE · WO eindeutig dokumentiert · WER · NACHWEIS** — je Anforderung. „erfüllt" nur, wenn ALLE fünf Dimensionen konkret beantwortet sind **und** operative Prozesse auf eine VA bzw. zentral gepflegte Werte auf Register/Baseline verweisen. Sobald eine Dimension fehlt/vage/doppeldeutig ist → mindestens „teilweise". | +| Runde | **2 (Korrektur der zu milden Runde 1)** | +| Erstellt | 2026-07-22 | +| Status | Review-Report (read-only) — es wurde **nichts** am Vorlagenpaket geändert; nur diese Report-Datei wurde neu erzeugt. | + +> Hinweis: Reiner Prüfbericht. Keine Datei des Vorlagenpakets, kein Code, keine DB, kein Seed wurde geändert; kein Commit, kein Push. Alle Textvorschläge sind einpflegefertig, aber **nicht** eingepflegt. + +--- + +## 1. Management-Summary + +Das Vorlagenpaket hat weiterhin einen **überdurchschnittlichen Reifegrad** (zentrale Baseline mit BL-IDs, zentrales Nachweisregister, 316 REQ-Anker ↔ 316 Mapping-IDs ohne Waisen, `-elev`-Blöcke für alle HOCH/SEHR-HOCH-Controls). Runde 1 hat diesen Reifegrad jedoch **zu wohlwollend** in Verdikte übersetzt: Sie hat Anforderungen als „erfüllt" gewertet, deren Umsetzungstext den strengen Rubric (eindeutiger Nachweisort, Inline-VA-Verweis, verwaltetes Register) nicht besteht. Runde 2 legt den skeptischen Maßstab konsequent an. + +**Was gegenüber Runde 1 strenger/korrigiert wurde:** + +- **8 Controls von „erfüllt" auf „teilweise" herabgestuft** (Details in §2): **1.2.3, 2.1.2, 3.1.1, 5.2.6, 5.2.8, 5.3.4-KI, 6.1.3, 7.1.2**. Die neue Control-Verteilung ist **14 erfüllt / 30 teilweise / 2 GAP** (Runde 1: 22 / 22 / 2). +- **Doppeldeutige Verortung** („im {{TOOL_TICKET}} **bzw.** ISMS-Tool") wird konsequent als **fehlender eindeutiger Nachweisort (G2)** gewertet — betrifft u. a. 1.2.3 und 1.6.1. +- **„Liste/Freigabeliste im ISMS-Tool"** ohne Register-ID, Pflichtattribute und Review-Turnus wird als **fehlendes verwaltetes Register (G4/G8)** gewertet — auch dort, wo Runde 1 „erfüllt" vergeben hatte (1.3.3, 1.3.4, 5.3.4, 5.3.4-KI, 6.1.3, 5.2.8, 5.2.7, 5.1.2). +- **Inline-VA-Verweis** wird control-genau geprüft: Von **23 Controls mit zuständiger VA** verweisen nur **8** im Umsetzungstext auf ihre VA; **15** nennen das Verfahren nur generisch bzw. im Anhang → G3. + +**Die drei in Runde 1 bestätigten Misses — in Runde 2 sauber aufgearbeitet:** + +1. **ISA 1.2.3 / R01 §3.3 (Informationssicherheit in Projekten):** In Runde 1 fälschlich „erfüllt". Tatsächlich deckt **keine VA** 1.2.3 ab (kein `FULFILLS 1.2.3` in den VA-Headern, kein Eintrag in `mapping.json → verfahren`). Der Umsetzungstext verortet doppeldeutig („die Einstufung wird im {{TOOL_TICKET}} **bzw. ISMS-Tool** dokumentiert"), und weder der genannte „dokumentierte Kriterienkatalog" noch ein **Projektregister/Projektverzeichnis** sind als verwaltetes Artefakt referenziert. → **Neu bewertet: teilweise**; Befund **G4** (neue VA „Informationssicherheit in Projekten") **+ G2/G8** (eindeutiger Nachweisort, Kriterienkatalog- und Projektregister). Textvorschläge in §8 (A-N1). +2. **Rendering-/Konsistenzbug `{{TOOL_TICKET}}` u. ä.:** Der Default von `{{TOOL_TICKET}}` ist **„das Ticketsystem"**; das Muster „im {{TOOL_TICKET}}" rendert daher zu **„im das Ticketsystem"** (Doppelartikel). Analog `{{TOOL_NAME}}` = „das ISMS-Tool" und `{{TOOL_IAM}}` = „das zentrale Verzeichnis …". Systemischer **G6**-Befund mit **11 konkreten Fundstellen** (§6), inkl. eines zusätzlichen Kasus-Fehlers bei `in {{TOOL_IAM}}` (R08:153). +3. **Software-Whitelist als verwaltetes Register mit Lieferantenbezug UND Asset-Kopplung:** Empfehlung **REG-SW-WHITELIST** mit Spalten u. a. Software, Version/Patch-Stand, **Quelle/Lieferant/Dienstleister**, Freigabestatus, Verantwortlich, Review — **doppelt cross-verlinkt** an **R13/VA-10 (Lieferantensteuerung)** (zugelassene Software hat einen steuerbaren Lieferanten) und an **R02/VA-08 (Asset & Klassifizierung)** (zugelassene Software ist als Asset geführt). Analog **REG-EXT-SERVICES** für externe/Cloud-/KI-Dienste (§5, §8 A-N3). + +**Reifegrad-Einschätzung Runde 2:** Inhaltlich bleibt die Abdeckung auf Ebene der 312 konsolidierten ISA-Zeilen hoch; die Herabstufungen betreffen überwiegend **Nachweisführung und Verortung** (Inline-Verweis, verwaltetes Register, eindeutiger Ort), nicht fehlenden Sachinhalt. Zwei echte Inhalts-GAPs bleiben (**2.1.1**, **3.1.3**). Mit der Roadmap in §7 erreicht das Paket ein durchgängig audittaugliches Niveau. + +--- + +## 2. Bewertungs-Übersicht + +### 2.1 Verteilung Control-Ebene (46 Controls) + +| Verdikt | Runde 1 | **Runde 2** | Controls (Runde 2) | +|---------|:------:|:-----------:|--------------------| +| **erfüllt** | 22 | **14** | 1.1.1; 1.2.1; 1.2.2; 3.1.4; 4.1.2; 5.1.1; 5.2.2; 5.2.3; 5.2.4; 5.2.5; 5.2.9; 5.3.3; 6.1.1; 7.1.1 | +| **teilweise** | 22 | **30** | 1.2.3; 1.3.1; 1.3.2; 1.3.3; 1.3.4; 1.4.1; 1.5.1; 1.5.2; 1.6.1; 1.6.2; 1.6.3; 2.1.2; 2.1.3; 2.1.4; 3.1.1; 4.1.1; 4.1.3; 4.2.1; 5.1.2; 5.2.1; 5.2.6; 5.2.7; 5.2.8; 5.3.1; 5.3.2; 5.3.4; 5.3.4-KI; 6.1.2; 6.1.3; 7.1.2 | +| **GAP** | 2 | **2** | 2.1.1; 3.1.3 | + +> Die 46 Controls = 45 Controls in `mapping.json` **+** der „Phantom"-Control **3.1.3** (IMPL-Stub in R07 ohne `REQ`-Anker und ohne `mapping.json`-Eintrag; siehe GAP G-B2). + +### 2.2 Gegenüber Runde 1 KORRIGIERTE Einstufungen (alle: erfüllt → teilweise/GAP) + +| Control | Richtlinie | Runde 1 | **Runde 2** | Grund der Verschärfung | GAP-Typ | +|---------|-----------|---------|-------------|------------------------|---------| +| **1.2.3** | R01 | erfüllt | **teilweise** | Keine VA deckt 1.2.3 ab; Verortung doppeldeutig („{{TOOL_TICKET}} bzw. ISMS-Tool"); Kriterienkatalog & Projektregister nicht als verwaltete Artefakte referenziert | G2, G4, G8, G6 | +| **2.1.2** | R05 | erfüllt | **teilweise** | „Ein Verfahren zum Umgang mit Verstößen ist beschrieben" — Verfahren nicht verortet/verlinkt (kein VA-/Dok-Verweis) | G1, G2 | +| **3.1.1** | R07 | erfüllt | **teilweise** | Zutrittsvergabe/-entzug (S1) und Besuchermanagement (S2) nur als „berücksichtigt" pauschaliert; kein Verfahren/VA verortet | G1, G3 | +| **5.2.6** | R10 | erfüllt | **teilweise** | VA-06 erfüllt laut `FULFILLS` 5.2.6-M1, wird im IMPL 5.2.6 aber **nicht** inline referenziert | G3 | +| **5.2.8** | R04 | erfüllt | **teilweise** | Kritische IT-Dienste nur „identifiziert"; kein verwaltetes Register (RTO/RPO nur im `-elev`-Block, keine BIA-Register-ID) | G8 | +| **5.3.4-KI** | R12 | erfüllt | **teilweise** | „Freigabeliste im ISMS-Tool" ist informelles Register ohne Register-ID/Attribute/Turnus (REG-EXT-SERVICES) | G8, G4 | +| **6.1.3** | R13 | erfüllt | **teilweise** | VA-10 erfüllt laut `FULFILLS` 6.1.3-M1, IMPL 6.1.3 verweist nicht inline; „Liste der IT-Dienste" (elev) informell | G3, G8 | +| **7.1.2** | R14 | erfüllt | **teilweise** | Kein referenzierter Prozess für Betroffenenrechte/Löschfristen-Review (nur BL-DEL-01 statisch); keine Datenschutz-Pflege-VA | G4 | + +### 2.3 Anforderungsebene (316 Einzelanforderungen) — Schwerpunkte + +- **Inline-VA-Verweis:** 23 Controls haben eine zuständige VA; **8** verweisen inline (5.1.1, 5.2.4, 5.2.5*, 5.2.8, 5.2.9, 5.3.4, 5.3.4-KI, 6.1.1), **15** nicht (G3). *5.2.5 verweist auf VA-06, nicht auf das ebenfalls zuständige VA-04. +- **Register/Baseline-Bezug fehlt (G8/G4)** bei allen „Liste im Tool"-Formulierungen: 1.2.3 (Kriterienkatalog/Projektregister), 1.3.3 & 5.3.4/5.3.4-KI (externe/Cloud/KI-Dienste), 1.3.4 (Software-Whitelist), 1.5.1 (Auditplan), 2.1.1 (sensible Rollen), 5.1.2 & 5.2.7 (Netz/Netzdienste), 5.2.8 & 6.1.3 (kritische IT-Dienste). +- **Leere Anforderung / Mapping-Bruch:** 3.1.3 (leerer `REQ`-Block, IMPL-Stub ohne Mapping); ISA **3.1.2** fehlt in R07 und `mapping.json` vollständig. +- **Strukturhinweis:** Control **1.1.1** (L00) hat **keinen gebündelten IMPL-Block**; `impl_anchor == req_anchor` — die „Umsetzung" ist die Leitlinien-Prosa selbst. Inhaltlich vertretbar (Leitlinie), aber vom übrigen `IMPL <control>`-Muster abweichend (siehe auch F-Tooling). + +--- + +## 3. Vollständige Verlinkungs-/Coverage-Matrix — ALLE 46 Controls + +Spalten: **Inline im Umsetzungstext verlinkt?** = verweist der `IMPL <control>`-Block per `{{LINK:VA-xx}}`/„siehe … Verfahren" auf die zuständige VA (ja) oder steht die VA nur generisch/im Anhang (nein); „n.a." = keine VA zuständig. + +| # | Control | Anf.-Stufe(n) | Zuständige VA (FULFILLS) | Inline verlinkt? | Register/Baseline-Bezug | Status | Bemerkung | +|--:|---------|---------------|--------------------------|:---------------:|--------------------------|--------|-----------| +| 1 | 1.1.1 | M×5 / S×4 | n.a. | n.a. | Nachweisregister; ISMS-Tool | erfüllt | Leitlinie; kein IMPL-Block (`impl_anchor=req_anchor`) | +| 2 | 1.2.1 | M×6 | n.a. | n.a. | ISMS-Tool; Managementbewertung | erfüllt | Governance vollständig verortet | +| 3 | 1.2.2 | M×4 / S×2 / H×1 | n.a. | n.a. | Rollenmatrix; ISMS-Tool | erfüllt | Funktionstrennung im `-elev` | +| 4 | 1.2.3 | M×1 / S×3 / H×1 | **keine** | **n.a. (VA fehlt)** | **kein Kriterienkatalog-/Projektregister; keine BL** | **teilweise** | **KORRIGIERT** v. erfüllt; G2/G4/G8/G6 (Miss #1) | +| 5 | 1.3.1 | M×2 / S×1 | VA-08 | **nein** | Asset-Inventar (ISMS-Tool) | teilweise | G3 | +| 6 | 1.3.2 | M×3 / S×1 | VA-08 | **nein** | Klassifizierungsschema | teilweise | G3 | +| 7 | 1.3.3 | M×2 / S×4 | n.a. | n.a. | „Freigabeliste im ISMS-Tool" (informell) | teilweise | G8/G4 → REG-EXT-SERVICES | +| 8 | 1.3.4 | M×2 / S×5 / V×1 | n.a. | n.a. | „Whitelist im ISMS-Tool" (informell) | teilweise | G8/G4 → REG-SW-WHITELIST (Miss #3) | +| 9 | 1.4.1 | M×4 / S×4 | VA-09 | **nein** | Risikoregister (ISMS-Tool) | teilweise | G3 | +| 10 | 1.5.1 | M×5 / S×1 | n.a. | n.a. | „Auditplan" (informell); keine BL-Frequenz | teilweise | G4/G2/G8 → VA-15, REG-AUDIT-PLAN | +| 11 | 1.5.2 | M×2 / S×1 | n.a. | n.a. | unabhängige Prüfung; kein Turnus/BL | teilweise | G2/G8 | +| 12 | 1.6.1 | M×3 / S×6 / V×1 | VA-01 | **nein** | Meldeweg; „{{TOOL_TICKET}} **bzw.** ISMS-Tool" | teilweise | G3/G2/G6 (doppeldeutig) | +| 13 | 1.6.2 | M×3 / S×3 / H×5 / V×1 | VA-01 | **nein** | {{TOOL_TICKET}} | teilweise | G3/G6 | +| 14 | 1.6.3 | M×3 / S×6 / H×5 / V×1 | VA-02 | **nein** | Krisenplan; keine BL-Übungsfrequenz | teilweise | G3/G8 | +| 15 | 2.1.1 | M×3 / S×2 | **keine** | **n.a. (VA fehlt)** | **kein Register sensibler Rollen** | **GAP** | G1/G2/G4/G5 → VA-14, REG-SENS-ROLES | +| 16 | 2.1.2 | M×2 / S×3 | n.a. | n.a. | Personalakte; Verstoß-„Verfahren" unverortet | **teilweise** | **KORRIGIERT** v. erfüllt; G1/G2 | +| 17 | 2.1.3 | M×1 / S×6 | VA-12 | **nein** | BL-HR-01; {{TOOL_NAME}} | teilweise | G3/G6 | +| 18 | 2.1.4 | M×1 / S×2 / H×1 | n.a. | n.a. | „eine Regelung" — nicht verortet | teilweise | G2/G1 | +| 19 | 3.1.1 | M×3 / S×5 / H×1 | n.a. | n.a. | BL-PHY-01/02; Besucher/Zutritt generisch | **teilweise** | **KORRIGIERT** v. erfüllt; G1/G3 → VA-17 | +| 20 | 3.1.3 | — (leer) | n.a. | n.a. | IMPL-Stub ohne REQ/Mapping | **GAP** | G6/G1; ISA 3.1.2 fehlt zudem ganz | +| 21 | 3.1.4 | M×1 / S×1 / H×1 | n.a. | n.a. | TECH_MDM; BL-EP-02 | erfüllt | Baseline-verankert | +| 22 | 4.1.1 | M×1 / S×1 / H×1 | VA-03 | **nein** | BL-IAM-07; TOOL_IAM | teilweise | G3 | +| 23 | 4.1.2 | M×2 / S×3 / H×1 / V×1 | n.a. | n.a. | BL-IAM-01/02; TECH_MFA | erfüllt | Baseline-verankert | +| 24 | 4.1.3 | M×7 / S×10 | VA-03 | **nein** | TOOL_IAM | teilweise | G3 | +| 25 | 4.2.1 | M×2 / S×5 / H×1 / V×2 | VA-03 | **nein** | BL-IAM-05; RECERT_FREQ | teilweise | G3 | +| 26 | 5.1.1 | M×1 / S×1 / H×1 | VA-07 | **ja** | BL-CRY-02/05 | erfüllt | Vorbildliche Referenzkette | +| 27 | 5.1.2 | M×3 / S×3 / H×1 / V×1 | VA-07 | **nein** | BL-CRY-01/04; Netzdienste informell | teilweise | G3/G8 → REG-NET | +| 28 | 5.2.1 | M×1 / S×4 / H×1 | VA-04 | **nein** | BL-OPS-09; {{TOOL_TICKET}} | teilweise | G3/G6 | +| 29 | 5.2.2 | M×2 / S×1 | n.a. | n.a. | Trennung Dev/Test/Prod | erfüllt | Konkret | +| 30 | 5.2.3 | M×2 / S×8 | n.a. | n.a. | BL-OPS-03; TECH_MALWARE | erfüllt | Baseline-verankert | +| 31 | 5.2.4 | M×5 / S×3 / H×2 / V×1 | VA-13 | **ja** | BL-OPS-04; LOG_RETENTION | erfüllt | Referenzkette vollständig | +| 32 | 5.2.5 | M×3 / S×3 | VA-04, VA-06 | **teils** | BL-OPS-01/02; PATCH_SLA_CRIT | erfüllt | VA-06 inline; VA-04 nicht inline | +| 33 | 5.2.6 | M×5 / S×3 / H×1 / V×1 | VA-06 | **nein** | BL-OPS-07/08; PENTEST_FREQ | **teilweise** | **KORRIGIERT** v. erfüllt; G3 | +| 34 | 5.2.7 | M×2 / S×2 / H×1 | n.a. | n.a. | BL-NET-01/02; „Netzplan" informell | teilweise | G8/G2 → REG-NET | +| 35 | 5.2.8 | M×2 / S×3 / H×7 / V×3 | VA-02 | **ja** | kein REG-CRIT-SERVICES; RTO/RPO nur elev | **teilweise** | **KORRIGIERT** v. erfüllt; G8 | +| 36 | 5.2.9 | M×2 / S×1 / H×2 / V×3 | VA-05 | **ja** | BL-OPS-05; BACKUP_SCHEME/RETENTION | erfüllt | Referenzkette vollständig | +| 37 | 5.3.1 | M×4 / S×5 / V×1 | n.a. | n.a. | {{TOOL_TICKET}}; keine Secure-Dev-VA | teilweise | G4/G1/G6 → VA-16 | +| 38 | 5.3.2 | M×1 / S×3 / H×1 | n.a. | n.a. | „über ein Verfahren" (generisch) | teilweise | G1/G4 → VA-16 | +| 39 | 5.3.3 | S×1 | n.a. | n.a. | BL-DEL-01; Löschprotokoll | erfüllt | Konkret | +| 40 | 5.3.4 | M×1 / S×1 | VA-11 | **ja** | „Freigabeliste im ISMS-Tool" (informell) | teilweise | G8 → REG-EXT-SERVICES | +| 41 | 5.3.4-KI | M×3 / S×1 | VA-11 | **ja** | „Freigabeliste im ISMS-Tool" (informell) | **teilweise** | **KORRIGIERT** v. erfüllt; G8/G4 | +| 42 | 6.1.1 | M×3 / S×2 / H×3 / V×2 | VA-10 | **ja** | BL-SUP-01; Lieferantenverzeichnis | erfüllt | Referenzkette vollständig | +| 43 | 6.1.2 | M×4 / S×5 | VA-10 | **nein** | NDAs „im ISMS-Tool" (informell) | teilweise | G3 | +| 44 | 6.1.3 | M×5 / S×2 / H×5 | VA-10 | **nein** | „Liste der IT-Dienste" (elev, informell) | **teilweise** | **KORRIGIERT** v. erfüllt; G3/G8 | +| 45 | 7.1.1 | M×2 / S×1 | n.a. | n.a. | Compliance-/Rechtsregister (ISMS-Tool) | erfüllt | Register vorhanden | +| 46 | 7.1.2 | M×3 | n.a. | n.a. | VVT (ISMS-Tool); BL-DEL-01 | **teilweise** | **KORRIGIERT** v. erfüllt; G4 (Betroffenenrechte/Löschfristen-Prozess) → VA-18 | + +--- + +## 4. GAP-Tabelle + +Legende Schwere: **hoch** = unmittelbar auditrelevant / Inhaltslücke · **mittel** = schwächt Nachweisführung / Konsistenz · **niedrig** = Feinschliff. +GAP-Typen: G1 zu generisch · G2 kein/eindeutiger Nachweisort fehlt · G3 fehlende Inline-Verlinkung · G4 fehlende VA/Register · G5 Verantwortlicher unklar · G6 Widerspruch/Redundanz/veraltet/Rendering · G7 Schutzbedarf nicht adressiert · G8 Baseline-/Register-Referenz fehlt. + +| # | Richtlinie | Control | Anf. (M/S/H/V) | Umsetzung heute (Kurz) | GAP-Typ | Schwere | Empfehlung | Konkreter Textvorschlag | Ziel-Referenz | +|---|-----------|---------|----------------|------------------------|---------|---------|------------|--------------------------|---------------| +| **N1** | R01 | **1.2.3** | M/S/H | „Klassifizierung anhand Kriterienkatalog; Einstufung im {{TOOL_TICKET}} **bzw. ISMS-Tool**; Maßnahmen als Aufgaben" — keine VA, doppeldeutiger Ort, Kriterienkatalog/Projektregister nicht referenziert | **G4, G2, G8, G6** | **hoch** | Neue VA „Informationssicherheit in Projekten"; Kriterienkatalog + Projektregister als verwaltete Artefakte; eindeutigen Ort setzen; Rendering fixen | siehe A-N1 | Neue **VA-19**, **REG-PROJECTS**, Kriterienkatalog (BL-PROJ-01) | +| G-B1 | R05 | 2.1.1 | M×3 / S×2 | „Sensible Tätigkeiten sind bestimmt; Eignung im rechtlich zulässigen Rahmen geprüft" — ohne Register, ohne Einstellungs-/Verifizierungs-VA, WER unklar | G1, G2, G4, G5 | **hoch** | Register sensibler Tätigkeitsbereiche + VA-14 (Eignungs-/Verifizierungsprozess) | siehe A-G-B1 | Neue **VA-14**, **REG-SENS-ROLES** | +| G-B2 | R07 | 3.1.3 | — (leer) | **Anforderungsblock leer**; IMPL-Stub ohne `REQ`/Mapping; **ISA 3.1.2 fehlt ganz** | G6, G1 | **hoch** | Scope 3.1.2/3.1.3 klären; REQ-Anker + Mapping ergänzen **oder** Stub entfernen | siehe A-G-B2 | `mapping.json`, R07 | +| N2 | R05 | 2.1.2 | M/S | „Ein Verfahren zum Umgang mit Verstößen ist beschrieben" — Verfahren nicht verortet/verlinkt | G1, G2 | mittel | Verstoß-/Disziplinarverfahren benennen & verorten (Dok/VA-14) | „… ein dokumentiertes Verfahren zum Umgang mit Verstößen **(siehe {{LINK:VA-14}})** ist etabliert; Nachweis in der Personalakte." | {{LINK:VA-14}} / Personalakte | +| N3 | R07 | 3.1.1 | M/S/H | Besuchermanagement, Zutrittsvergabe/-entzug (S1/S2) nur als „berücksichtigt" pauschaliert | G1, G3 | mittel | Zutritts-/Besuchermanagement-Verfahren verorten | „… Zutrittsrechte werden über {{TOOL_TICKET}} vergeben/entzogen **(Ablauf siehe {{LINK:VA-17}})**; Besuchermanagement (Registrierung/Begleitung) ist geregelt (BL-PHY-…)." | Neue **VA-17** | +| N4 | R10 | 5.2.6 | M/S/H/V | Härtung/technische Prüfungen; VA-06 erfüllt 5.2.6-M1, aber **nicht inline** referenziert | G3 | mittel | VA-06 im IMPL 5.2.6 inline referenzieren | „… risikoorientiert geprüft **(siehe {{LINK:VA-06}})**; Ergebnisse werden gespeichert, der Leitung berichtet …" | {{LINK:VA-06}} | +| N5 | R04 | 5.2.8 | M/S/H/V | Kritische IT-Dienste „identifiziert"; RTO/RPO nur im `-elev`-Block; kein Register | G8 | mittel | Register kritischer IT-Dienste inkl. BIA/RTO/RPO referenzieren | „Kritische IT-Dienste sind mit Geschäftsauswirkung im **Register kritischer IT-Dienste ({{LINK:REG-CRIT-SERVICES}})** (inkl. RTO/RPO, Wiederanlaufreihenfolge) erfasst … (siehe {{LINK:VA-02}})." | **REG-CRIT-SERVICES** | +| N6 | R12 | 5.3.4-KI | M/S | „Freigabeliste im ISMS-Tool" ohne Register-ID/Attribute/Turnus | G8, G4 | mittel | KI-/externe Dienste als verwaltetes Register mit Lieferant+Asset-Kopplung | siehe A-N6 | **REG-EXT-SERVICES**, {{LINK:VA-11}} | +| N7 | R13 | 6.1.3 | M/S/H | VA-10 erfüllt 6.1.3-M1, IMPL nicht inline; „Liste IT-Dienste/Dienstleister" (elev) informell | G3, G8 | mittel | VA-10 inline; Dienste-/Dienstleister-Register formalisieren | „… Verantwortlichkeiten … definiert **(siehe {{LINK:VA-10}})**; betroffene IT-Dienste und Dienstleister im **{{LINK:REG-EXT-SERVICES}}** geführt." | {{LINK:VA-10}}, **REG-EXT-SERVICES** | +| N8 | R14 | 7.1.2 | M | VVT im Tool; kein referenzierter Prozess für Betroffenenrechte/Löschfristen-Review | G4 | mittel | Datenschutz-/Compliance-Pflege-VA referenzieren | siehe A-N8 | Neue **VA-18** | +| N9 | R09 | 5.1.2 | M/S/H/V | VA-07 erfüllt 5.1.2-M1/S1, IMPL 5.1.2 verweist nicht inline; Netzdienste nur „identifiziert" | G3, G8 | mittel | VA-07 inline; Netzdienste-Register | „Genutzte Netzdienste sind im **{{LINK:REG-NET}}** identifiziert/dokumentiert; Krypto-/Schlüsselverwaltung **(siehe {{LINK:VA-07}})**." | {{LINK:VA-07}}, **REG-NET** | +| F3 | R02 | 1.3.1, 1.3.2 | M/S | IMPL ohne Inline-Verweis auf VA-08 | G3 | mittel | VA-08 im Umsetzungstext inline referenzieren | „… als Katalog gepflegt **(siehe {{LINK:VA-08}})**; Zu-/Abgänge über {{TOOL_TICKET}}." | {{LINK:VA-08}} | +| F4 | R03 | 1.4.1 | M/S | „Das dokumentierte Risikomanagement-Verfahren …" ohne Inline-Link auf VA-09 | G3 | mittel | VA-09 inline referenzieren | „Das dokumentierte Risikomanagement-Verfahren **(siehe {{LINK:VA-09}})** …" | {{LINK:VA-09}} | +| F5 | R04 | 1.6.1, 1.6.2 | M/S/H/V | „nach einem definierten Incident-Verfahren im {{TOOL_TICKET}}" ohne Inline-Link auf VA-01 | G3 | mittel | VA-01 inline referenzieren | „… nach einem definierten Incident-Verfahren **(siehe {{LINK:VA-01}})** … behandelt und dokumentiert." | {{LINK:VA-01}} | +| F6 | R04 | 1.6.3 | M/S/H/V | Krisenmanagement generisch; VA-02 nur im Anhang | G3, G8 | mittel | VA-02 inline; Übungsfrequenz in Baseline | „Ein Krisenmanagement … ist etabliert **(Auslösung/Wiederanlauf siehe {{LINK:VA-02}})** (Übungen BL-IR-01)." | {{LINK:VA-02}}, **BL-IR-01** | +| F7 | R05 | 2.1.3 | M/S | Awareness stark (BL-HR-01); VA-12 nur im Anhang | G3 | mittel | VA-12 inline referenzieren | „… mindestens {{REVIEW_CYCLE}} … geschult **(Ablauf siehe {{LINK:VA-12}})**." | {{LINK:VA-12}} | +| F8 | R08 | 4.1.1, 4.1.3, 4.2.1 | M/S/H/V | JML/Rezertifizierung stark, aber VA-03 nur im Anhang | G3 | mittel | VA-03 inline referenzieren | „Benutzerkonten werden über einen definierten Lebenszyklus (Joiner/Mover/Leaver) **(siehe {{LINK:VA-03}})** … verwaltet." | {{LINK:VA-03}} | +| F9 | R10 | 5.2.1 | M/S/H | „formales Change-Verfahren … im {{TOOL_TICKET}} (BL-OPS-09)" ohne Inline-Link auf VA-04 | G3 | mittel | VA-04 inline referenzieren | „Änderungen durchlaufen ein formales Change-Verfahren **(siehe {{LINK:VA-04}})** …" | {{LINK:VA-04}} | +| F10 | R02 | 1.3.4 | M/S/V | „Liste zugelassener Software (Whitelist) … im ISMS-Tool" ohne Register-ID, Lieferant/Freigabestatus | G8, G4 | mittel | REG-SW-WHITELIST mit Lieferant- UND Asset-Kopplung | siehe A-N3 (Miss #3) | **REG-SW-WHITELIST** | +| F11 | R02 / R12 | 1.3.3 / 5.3.4 | M/S | „Freigabeliste im ISMS-Tool" für externe/Cloud-/KI-Dienste — generisch | G8, G4 | mittel | Gemeinsames REG-EXT-SERVICES mit Schutzbedarf/Exit/Lieferant | siehe A-N6 | **REG-EXT-SERVICES**, {{LINK:VA-11}} | +| F12 | R03 | 1.5.1, 1.5.2 | M/S | Audits „nach einem Auditplan"; kein Audit-Verfahren, keine Verortung/Frequenz | G2, G4, G8 | mittel | Audit-Verfahren (VA-15) + Audit-Programm-Register + Baseline-Frequenz | siehe A-F12 | Neue **VA-15**, **REG-AUDIT-PLAN**, **BL-GOV-01** | +| F13 | R11 | 5.3.1, 5.3.2 | M/S/H/V | Security-by-Design/Abnahme, aber keine VA; 5.3.2 „über ein Verfahren umgesetzt" | G4, G1 | mittel | VA-16 (Sichere Beschaffung/Entwicklung & Abnahme) inline | siehe A-F13 | Neue **VA-16** | +| F14 | R09 / R10 | 5.1.2 / 5.2.7 | M/S/H | „Netzplan/Segmentierungskonzept wird gepflegt", „Netzdienste identifiziert" — ohne Register-ID | G2, G8 | niedrig | Verwaltetes Netz-/Netzdienste-Register mit Turnus | „… ein aktueller Netzplan/Segmentierungskonzept wird im **{{LINK:REG-NET}}** gepflegt (Review {{REVIEW_CYCLE}})." | **REG-NET** | +| F16 | R06 | 2.1.4 | M/S/H | „Mobiles Arbeiten ist in einer Regelung festgelegt" — welche, wo? | G2, G1 | niedrig | Regelung konkret benennen/verorten | „Mobiles Arbeiten ist in der **Regelung mobiles Arbeiten (im ISMS-Tool ({{TOOL_NAME}}) hinterlegt)** festgelegt …" | {{TOOL_NAME}} | +| F17 | — (Tooling) | — | — | `mapping.json` ohne `implementation`-Feld (0/316); Integrationsleitfaden §5/§8 setzt es voraus (Assessment-Export) | G6 | mittel | Feld `implementation` ergänzen **oder** Leitfaden korrigieren (`impl_anchor`-Auflösung dokumentieren) | siehe A-F17 | `mapping.json` / `00_Integrationsleitfaden_Wizard.md` | +| F18 | Alle (elev) | div. | H/V | `-elev`-Blöcke mischen HOCH- und SEHR-HOCH-Sätze unter **einem** `FLAG_ELEVATED_PROTECTION`; bei nur HOCH erscheint „Bei sehr hohem Schutzbedarf …" | G6, G7 | niedrig | SEHR-HOCH-Sätze in `{{#if FLAG_VERY_HIGH_PROTECTION}}` auslagern | siehe A-F18 | R04/R08/R10 u. a. `-elev`-Blöcke | +| F19 | R13 | 6.1.2 | M/S | NDA-Prozess stark; VA-10 deckt 6.1.2-M1/S1, IMPL nicht inline | G3 | niedrig | VA-10 auch bei NDA inline referenzieren | „… gültige NDAs auf Basis geprüfter Standardvorlagen **(Ablauf siehe {{LINK:VA-10}})** …" | {{LINK:VA-10}} | +| F21 | VA-10 | 6.1.x | — | RACI-Schritttexte in der Tabelle abgeschnitten („… (Schutzb", „…(Selbstauskunft/Nac") | G6 | niedrig | Spaltentext vervollständigen | RACI-Schrittbezeichnungen ausschreiben | VA-10 | +| **R-1..R-11** | R01/R04/R05/R08/R10/R11 | div. | — | **Rendering-Doppelartikel** „im {{TOOL_TICKET/TOOL_NAME/TOOL_IAM}}" → „im **das** …" | G6 | mittel | Präposition anpassen (siehe §6) | „… dokumentiert **im Ticketsystem ({{TOOL_TICKET}})** …" bzw. „… **im {{TOOL_TICKET}}**" → „… **in {{TOOL_TICKET}}**"-Muster entschärfen | §6 | + +--- + +## 5. Empfohlene neue VAs / Register + +### 5.1 Neue Verfahrensanweisungen + +| ID | Titel | Zweck | Betroffene Controls | Priorität | +|----|-------|-------|---------------------|-----------| +| **VA-19** *(NEU, Miss #1)* | **Informationssicherheit in Projekten** | Projektklassifizierung nach dokumentiertem Kriterienkatalog; Risikobewertung in früher Phase & bei Änderungen; Maßnahmenableitung/-verfolgung; Pflege des Projektregisters; ISB-Einbindung bei erhöhtem Schutzbedarf | 1.2.3 (M1, S1–S3, H1) | **hoch** | +| **VA-14** | Personalsicherheit – Eignungsprüfung & sensible Tätigkeiten | Definition sensibler Bereiche; Einstellungs-/Verifizierungsprozess (Identität, Referenzen, Führungszeugnis im rechtlich zulässigen Rahmen); Umgang mit Verstößen gegen IS-/Vertraulichkeitspflichten | 2.1.1 (M1–M3, S1–S2), 2.1.2 | **hoch** | +| **VA-15** | Interne Audits & Complianceprüfungen | Auditprogramm, -planung, Durchführung, Berichterstattung, Maßnahmenverfolgung; unabhängige Überprüfung | 1.5.1 (M1–M5, S1), 1.5.2 (M1–M2, S1) | mittel | +| **VA-16** | Sichere Beschaffung, Entwicklung & Abnahme | Sicherheitsanforderungen in Design/Beschaffung/Änderung; Abnahmetests; (bei Eigenentwicklung) Secure-Coding/SAST/Dependency-Scan; Testdaten-Handling | 5.3.1 (M1–M4, S1–S5, V1), 5.3.2 | mittel | +| **VA-17** *(optional)* | Zutritts- & Besuchermanagement (physisch) | Vergabe/Entzug Zutrittsrechte, Besucherregistrierung/-begleitung, Umgang mit Betriebsmitteln | 3.1.1 (S1–S5), 3.1.3 | niedrig | +| **VA-18** *(optional)* | Datenschutz- & Compliance-Pflege | Rechtsregister-Review, Löschfristen/Löschkonzept, Betroffenenrechte, VVT-Pflege | 7.1.1, 7.1.2 | niedrig | + +### 5.2 Neue / zu formalisierende Register + +| Register-ID | Inhalt / Pflichtattribute | Cross-Link | Ersetzt heutige Formulierung in | Priorität | +|-------------|---------------------------|-----------|----------------------------------|-----------| +| **REG-SW-WHITELIST** *(Miss #3)* | Software, Version/Patch-Stand, **Quelle/Lieferant/Dienstleister**, Freigabestatus, Freigeber/Verantwortlich, Review-Datum | **R13/VA-10** (Lieferant steuerbar) **+ R02/VA-08** (als Asset geführt) | R02 1.3.4 („Liste zugelassener Software") | mittel | +| **REG-EXT-SERVICES** *(Miss #3 analog)* | Externe/Cloud/KI-Dienste: Schutzbedarf, Datenlokation (EU), Verschlüsselung, Exit-Strategie, **Quelle/Lieferant**, Freigabestatus, Freigeber | **R13/VA-10 + R02/VA-08** | R02 1.3.3; R12 5.3.4 / 5.3.4-KI; R13 6.1.3 | mittel | +| **REG-SENS-ROLES** | Sensible Tätigkeitsbereiche/Rollen, geforderte Eignungsnachweise, Prüftiefe | R05/VA-14 | R05 2.1.1 | **hoch** | +| **REG-PROJECTS** *(NEU, Miss #1)* | Projekte, IS-Klassifizierung, Risikobewertung, abgeleitete Maßnahmen/Status, ISB-Einbindung | R01/VA-19 | R01 1.2.3 | **hoch** | +| **REG-CRIT-SERVICES** | Kritische IT-Dienste, BIA-Einstufung, RTO/RPO, Abhängigkeiten, Wiederanlaufreihenfolge | R04/VA-02 | R04 5.2.8; R13 6.1.3 | mittel | +| **REG-NET** | Netzplan/Segmentierung, Netzdienste, Zonen, Review-Turnus | R09/R10, VA-07 | R09 5.1.2; R10 5.2.7 | niedrig | +| **REG-AUDIT-PLAN** | Auditprogramm: Zeitplan, Umfang, geprüfte Controls, Prüfer, Ergebnisse | R03/VA-15 | R03 1.5.1 (S1) | mittel | + +> Mehrere „Register" existieren heute implizit als Datensätze im ISMS-Tool. Empfehlung: als **benannte, verwaltete Register mit Register-ID** führen und über `{{LINK:REG-…}}` konsistent referenzieren (analog zur Baseline-/VA-Mechanik). Dazu Link-Auflösungstabelle (Integrationsleitfaden §6) und ggf. `variables.schema.json` um die neuen Ziele erweitern. + +### 5.3 Ergänzung Baseline + +| BL-ID | Parameter | Vorschlag | +|-------|-----------|-----------| +| **BL-GOV-01** | Audit-/Prüfzyklus | Interne Prüfung {{REVIEW_CYCLE}}; unabhängige Prüfung/Assessment mind. alle 3 Jahre bzw. nach grundlegenden Änderungen | +| **BL-IR-01** | Krisen-/Notfallübungen | Tabletop {{REVIEW_CYCLE}} (HOCH); Vollübung mit Entscheidungsträgern (SEHR HOCH) | +| **BL-PROJ-01** | Projekt-Klassifizierungskriterien | Dokumentierter Kriterienkatalog zur IS-Klassifizierung von Projekten (Auslöser/Schwellen für ISB-Einbindung) | + +--- + +## 6. Konsistenz-/Rendering-Befunde (G6) + +**Ursache:** Mehrere Variablen-Defaults beginnen bereits mit einem Artikel: `{{TOOL_TICKET}}`=„das Ticketsystem", `{{TOOL_NAME}}`=„das ISMS-Tool", `{{TOOL_IAM}}`=„das zentrale Verzeichnis (Entra ID / Active Directory)", `{{TECH_MDM}}`=„das eingesetzte MDM", `{{TECH_MFA}}`=„die eingesetzte MFA-Lösung" usw. Steht davor eine kontrahierte Präposition („im", „in"), entsteht beim Rendern ein **Doppelartikel** („im **das** Ticketsystem") bzw. ein Kasus-Fehler. + +**Konkrete Fundstellen (Datei : Zeile — Control):** + +| # | Fundstelle | Muster (rendert zu) | Control | +|---|-----------|----------------------|---------| +| R-1 | R01_ISMS-Organisation-und-Rollen.md:110 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" (**2×** in der Zeile) | 1.2.3 | +| R-2 | R04_Incident-…:69 | „im {{TOOL_TICKET}} **bzw. ISMS-Tool**" (Doppelartikel **+** doppeldeutiger Ort G2) | 1.6.1 | +| R-3 | R04_Incident-…:126 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" | 1.6.2 | +| R-4 | R05_Personalsicherheit-…:111 | „im {{TOOL_NAME}}" → „im **das** ISMS-Tool" | 2.1.3 | +| R-5 | R08_Identitaets-…:45 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" | 4.1.1 | +| R-6 | R08_Identitaets-…:153 | „**in** {{TOOL_IAM}}" → „in **das** zentrale Verzeichnis …" (Doppelartikel **+** Kasus: müsste „im zentralen Verzeichnis") | 4.1.3 | +| R-7 | R08_Identitaets-…:199 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" | 4.2.1 | +| R-8 | R10_Betriebssicherheit.md:57 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" | 5.2.1 | +| R-9 | R10_Betriebssicherheit.md:203 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" | 5.2.5 | +| R-10 | R11_Sichere-Systembeschaffung-…:67 | „im {{TOOL_TICKET}}" → „im **das** Ticketsystem" | 5.3.1 | +| R-11 | R01_…:110 (2. Vorkommen) | „als Aufgaben im {{TOOL_TICKET}} nachgehalten" → „im **das** …" | 1.2.3 | + +> **Zusätzlich doppeldeutig verortet (G2, „… bzw. ISMS-Tool"):** R01:110 („im {{TOOL_TICKET}} **bzw. ISMS-Tool**") und R04:69 („Formular im {{TOOL_TICKET}} **bzw. ISMS-Tool**"). Diese Stellen brechen den Grundsatz „ein Nachweisort je Sachverhalt" und sind Auslöser der Herabstufung von 1.2.3 (und Mitgrund bei 1.6.1). +> +> **Grammatikalisch unkritisch** (kein Fix nötig) sind Vorkommen ohne kontrahierte Präposition, z. B. „über {{TOOL_IAM}}", „und {{TOOL_TICKET}}", „{{TOOL_TICKET}}-Aufträge" — hier passt der eingebettete Artikel bzw. es entsteht keine Doppelung. + +**Empfohlener Fix (zwei Varianten):** +- **Variante A (Text):** Präpositionsmuster „im {{VAR}}" → „**in {{VAR}}**" bzw. Artikel explizit ausschreiben: „**im Ticketsystem ({{TOOL_TICKET}})**". Bei R08:153 zusätzlich Kasus/Präposition „**im** {{TOOL_IAM}}" verwenden. +- **Variante B (Daten):** Variablen-Defaults ohne führenden Artikel definieren (`{{TOOL_TICKET}}`=„Ticketsystem") und Artikel im Fließtext setzen. **Achtung:** wirkt global auf alle Fundstellen; nur konsistent umsetzen. + +--- + +## 7. Priorisierte Roadmap + +**Priorität 1 — Inhalts-GAPs & Fehleinstufungen mit hoher Auditrelevanz:** +1. **N1 / VA-19 / REG-PROJECTS** — R01 1.2.3 Informationssicherheit in Projekten: VA anlegen, Kriterienkatalog (BL-PROJ-01) + Projektregister formalisieren, eindeutigen Ort setzen, Rendering fixen. *(Miss #1)* +2. **G-B1 / VA-14 / REG-SENS-ROLES** — R05 2.1.1 Personalsicherheit konkretisieren. +3. **G-B2** — R07 3.1.3 leeren Anforderungsblock beheben; ISA-Scope 3.1.2/3.1.3 klären; Mapping ergänzen oder Stub entfernen. + +**Priorität 2 — Nachweiskette & Konsistenz (geringer Aufwand, hoher Nutzen):** +4. **F3–F9, F19, N4, N7, N9** — Inline-Verlinkung der Verfahren in den 15 Umsetzungstexten vereinheitlichen (VA-01/02/03/04/06/07/08/09/10/12). +5. **§6 / R-1..R-11** — Rendering-Doppelartikel `{{TOOL_TICKET}}` u. ä. beheben; doppeldeutige Orte („bzw. ISMS-Tool") auflösen. *(Miss #2)* +6. **F17** — `mapping.json` ↔ Integrationsleitfaden abgleichen (`implementation`-Feld ergänzen oder Leitfaden korrigieren). + +**Priorität 3 — Register formalisieren (Reifegrad):** +7. **F10/F11/N5/N6/N7 / REG-SW-WHITELIST, REG-EXT-SERVICES, REG-CRIT-SERVICES, REG-NET** — verwaltete Register mit Pflichtattributen + `{{LINK:REG-…}}`; **REG-SW-WHITELIST/REG-EXT-SERVICES mit Lieferant- UND Asset-Kopplung**. *(Miss #3)* +8. **F12 / VA-15 / REG-AUDIT-PLAN / BL-GOV-01** und **F13 / VA-16** — Audit- und Secure-Development-Verfahren. + +**Priorität 4 — Feinschliff:** +9. **N2, N3, N8, F14, F16, F18, F21** — Verstoß-Verfahren verorten; VA-17/VA-18 (optional); Netz-/mobile-Regelung verorten; SEHR-HOCH-`{{#if}}`-Trennung; VA-10 RACI-Text. + +--- + +## 8. Anhang: Einfügefertige Textvorschläge + +Alle Vorschläge im bestehenden Stil (Variablen `{{…}}`, Baseline-/VA-/Register-Verweise), **nicht** eingepflegt. + +### A-N1 — R01 §3.3 (ISA 1.2.3), IMPL 1.2.3 (Ersatztext, Miss #1) + +> Projekte werden zu Beginn anhand des **dokumentierten Kriterienkatalogs (BL-PROJ-01)** hinsichtlich Informationssicherheitsbedarf klassifiziert; Einstufung, Risikobewertung und abgeleitete Maßnahmen werden im **Projektregister ({{LINK:REG-PROJECTS}})** geführt. In einer frühen Projektphase und bei Änderungen erfolgt eine Risikobewertung nach dem **Verfahren Informationssicherheit in Projekten ({{LINK:VA-19}})**; Maßnahmen werden als Aufgaben **in {{TOOL_TICKET}}** nachgehalten und vor Projektabschluss geprüft. Verantwortlich ist die Projektleitung; bei erhöhtem Schutzbedarf wird {{ROLE_ISB}} eingebunden. + +*Ergänzung Abschnitt 8 „Verwandte Dokumente" von R01:* `- Zugehörige Verfahren: {{LINK:VA-19}}; Register: {{LINK:REG-PROJECTS}}` + +*Hinweis:* Damit entfällt die doppeldeutige Verortung („{{TOOL_TICKET}} bzw. ISMS-Tool"), der Kriterienkatalog wird als Baseline-Artefakt (BL-PROJ-01) geführt, und die fehlende VA/das fehlende Register werden geschlossen. + +### A-G-B1 — R05 3.1 (ISA 2.1.1), IMPL 2.1.1 (Ersatztext) + +> Sensible Arbeitsbereiche und Tätigkeiten sind im **Register sensibler Tätigkeiten ({{LINK:REG-SENS-ROLES}})** bestimmt und mit der geforderten Prüftiefe hinterlegt; Anforderungen an Positionen sind in Stellenbeschreibungen dokumentiert und werden erfüllt. Identitätsverifizierung sowie die persönliche und – bei sensiblen Rollen – erweiterte Eignungsprüfung (Gespräch, Referenzen, Führungszeugnis im rechtlich zulässigen Rahmen) erfolgen nach dem **Eignungs- und Verifizierungsverfahren ({{LINK:VA-14}})**; Verantwortlich: {{ROLE_HR_LEAD}}; Nachweis in der Personalakte. + +### A-G-B2 — R07 3.2 (ISA 3.1.3) Anforderungsblock (heute leer) + +**(a) Falls 3.1.3 im ISA-Scope ist** — Anforderungstext + Anker ergänzen und `mapping.json`-Einträge nachziehen: +> `<!-- REQ 3.1.3-M1 -->` +> - **[MUSS]** Der Umgang mit unterstützenden Betriebsmitteln (z. B. Verkabelung, Strom-/Klimaversorgung, Serverräume) ist bestimmt; Schutz gegen Ausfall, Wartung und Überwachung sind geregelt. + +**(b) Falls 3.1.3 nicht im Scope ist** — Abschnitt 3.2 samt IMPL-Stub entfernen, damit kein Umsetzungstext ohne zugehörige Anforderung/Mapping verbleibt. + +In beiden Fällen: Klären, ob **ISA 3.1.2** bewusst ausgelassen ist (fehlt in R07 und `mapping.json`) und dokumentieren. + +### A-N3 — R02 3.4 (ISA 1.3.4), IMPL 1.3.4 (REG-SW-WHITELIST, Miss #3) + +> Software (inkl. Spezial-/Wartungssoftware) wird vor Einsatz freigegeben. Zugelassene Software wird im **Register Software-Whitelist ({{LINK:REG-SW-WHITELIST}})** mit Version/Patch-Stand, **Quelle/Lieferant**, Freigabestatus und Freigeber geführt; jeder Eintrag ist mit dem verantwortlichen **Lieferanten ({{LINK:VA-10}} / {{LINK:R13}})** und – als verwaltetes Asset – mit dem **Asset-Inventar ({{LINK:VA-08}} / {{LINK:R02}})** verknüpft. Beschaffung/Freigabe läuft über {{TOOL_TICKET}}; Repositorys sind gegen Manipulation geschützt; Verantwortlich: {{ROLE_IT_LEAD}}; Review {{REVIEW_CYCLE}}. + +### A-N6 — R12 3.1 (ISA 5.3.4 / 5.3.4-KI), IMPL (REG-EXT-SERVICES) + +> … Cloud-/KI-Dienste werden vor Nutzung bewertet (Schutzbedarf, Datenlokation/EU, Verschlüsselung, Exit) und von {{ROLE_ISB}} freigegeben; Freigaben werden im **Register externe IT-/Cloud-/KI-Dienste ({{LINK:REG-EXT-SERVICES}})** mit Schutzbedarf, Datenlokation, **Quelle/Lieferant**, Freigabestatus und Freigeber geführt und mit **Lieferantensteuerung ({{LINK:VA-10}})** sowie **Asset-Inventar ({{LINK:VA-08}})** verknüpft (Ablauf siehe {{LINK:VA-11}}); die ausschließliche Nutzung freigegebener Dienste wird {{REVIEW_CYCLE}} geprüft. + +### A-N8 — R14 (ISA 7.1.2), IMPL 7.1.2 (Datenschutz-Pflege-VA) + +> … das Verzeichnis der Verarbeitungstätigkeiten wird im ISMS-Tool ({{TOOL_NAME}}) geführt, TOM und Löschkonzepte (BL-DEL-01) sind geregelt; Rechtsregister-Review, Löschfristen und Betroffenenrechte werden nach dem **Datenschutz-/Compliance-Pflegeverfahren ({{LINK:VA-18}})** bearbeitet; Verantwortlich: {{ROLE_DPO}}. + +### A-F12 — R03 3.2 (ISA 1.5.1), IMPL 1.5.1 (VA-/Register-Verweis) + +> Die Einhaltung von Richtlinien, Verfahren und technischen Anforderungen wird organisationsweit nach dem **Audit-Programm ({{LINK:REG-AUDIT-PLAN}})** und dem **Audit-/Complianceprüfungs-Verfahren ({{LINK:VA-15}})** durch interne Audits und Kontrollen regelmäßig überprüft (Turnus BL-GOV-01); Ergebnisse werden aufgezeichnet und aufbewahrt, Abweichungen als Maßnahmen im {{TOOL_NAME}} nachverfolgt; Verantwortlich: {{ROLE_ISB}}. + +### A-F13 — R11 3.1 (ISA 5.3.1), IMPL 5.3.1 (VA-Verweis) + +> Informationssicherheitsanforderungen sind fester Bestandteil von Design, Beschaffung, Erweiterung und Änderung von IT-Diensten (Security by Design); Anforderungsspezifikation, Prüfung und Abnahmetests unter Sicherheitsaspekten erfolgen nach dem **Verfahren Sichere Beschaffung/Entwicklung & Abnahme ({{LINK:VA-16}})**; Produktivsetzung erst nach Prüfung **in {{TOOL_TICKET}}**. Produktivdaten in Tests werden vermieden/anonymisiert, Testsysteme angemessen geschützt.{{#if FLAG_DEV_INHOUSE}} Für die Eigenentwicklung gelten Secure-Coding-Vorgaben mit Code-Reviews und automatisierten Sicherheitstests (SAST/Dependency-Scan) gemäß {{LINK:VA-16}}.{{/if}} + +### A-F17 — `mapping.json` / Integrationsleitfaden + +**Variante 1 (Daten an Leitfaden angleichen):** je Anforderung ein Feld `implementation` mit dem gebündelten Umsetzungstext (bzw. eindeutiger Kennung des Control-IMPL-Blocks) aufnehmen, damit der Assessment-Export (§8, „Implementation description") direkt aus `mapping.json` speisbar ist. + +**Variante 2 (Leitfaden an Daten angleichen, geringerer Aufwand):** In §5/§8 dokumentieren, dass `implementation` **nicht** in `mapping.json` liegt, sondern zur Laufzeit über `impl_anchor` (control-gebündelter Anker `IMPL <control>`) aus der jeweiligen `.md` aufgelöst wird. **Zusätzlich klären:** Für Control **1.1.1** ist `impl_anchor == req_anchor` (kein `IMPL 1.1.1`-Block; Leitlinien-Prosa) — diese Sonderauflösung im Leitfaden explizit ausweisen. + +### A-F18 — Trennung SEHR-HOCH in `-elev`-Blöcken (Muster) + +Statt eines gemeinsamen `{{#if FLAG_ELEVATED_PROTECTION}}`-Blocks, der HOCH- und SEHR-HOCH-Sätze mischt: + +> `{{#if FLAG_HIGH_PROTECTION}}` … HOCH-Umsetzungssätze … `{{/if}}` +> `{{#if FLAG_VERY_HIGH_PROTECTION}}` … „Bei sehr hohem Schutzbedarf …" … `{{/if}}` + +So erscheint der SEHR-HOCH-Umsetzungstext nur, wenn auch die zugehörigen `[SEHR HOCH]`-Anforderungen im Set sind (betrifft u. a. IMPL 1.2.2-elev, 1.6.2-elev, 1.6.3-elev, 4.1.2-elev, 4.2.1-elev, 5.1.2-elev, 5.2.4-elev, 5.2.6-elev, 5.2.9-elev, 6.1.1-elev). + +--- + +## 9. Positiv-Befunde (zur Absicherung, kein Handlungsbedarf) + +- **Baseline-Disziplin:** konkrete Werte durchgängig in `Technische-Sicherheits-Baseline.md` zentralisiert (31 BL-IDs); Umsetzungstexte referenzieren korrekt (z. B. R08 4.1.2 → BL-IAM-01/02, R10 5.2.9 → BL-OPS-05). +- **Vorbildliche Referenzketten:** 5.1.1, 5.2.4, 5.2.8, 5.2.9, 6.1.1 verbinden IMPL ↔ VA ↔ Baseline eindeutig — Zielbild für die übrigen Controls. +- **Mapping-Integrität:** 316 REQ-Anker ↔ 316 Mapping-IDs, keine Waisen (verifiziert); VA-`FULFILLS`-Header stimmen mit `mapping.json → verfahren` überein. +- **Schutzbedarf:** `-elev`-Abdeckung für alle Controls mit HOCH/SEHR-HOCH-Anforderungen vorhanden (Trennungs-Feinschliff siehe F18). +- **KI-/GenAI-Ergänzung (R12 3.2)** inhaltlich stark und aktuell (Datenklassen je Dienst, kein Training auf Eingaben, Human-in-the-Loop, EU AI Act) — die Herabstufung von 5.3.4-KI betrifft ausschließlich die Register-Formalisierung, nicht den Sachinhalt. diff --git a/docs/sicherheit/Aufgabenpaket-Sicherheit-Administration.md b/docs/sicherheit/Aufgabenpaket-Sicherheit-Administration.md new file mode 100644 index 0000000..5bca7da --- /dev/null +++ b/docs/sicherheit/Aufgabenpaket-Sicherheit-Administration.md @@ -0,0 +1,78 @@ +# Umsetzungspaket — Sicherheit & Administration (1 Entwickler) + +> Claude-Code-Prompt. Basis-Branch **`dev`**; je Story ein Feature-Branch `dev/sec<n>-…` (PR-Ziel `dev`). Grundlage: `Sicherheit-und-Administration-Konzept.md` + Ist-Stand `STAND-dev-branch.md`. +> **Entscheidungen (fix):** Mail via **SMTP** · **1 Entwickler** (sequenziell) · **2FA bleibt optional**, aber **pro Tenant im Adminportal als Pflicht** einstellbar · **Passkeys** dabei · **DSGVO-Funktionen** dabei. + +## Vorhandenes wiederverwenden (nicht neu bauen) +- **MFA-Kern** (TOTP + Recovery-Codes) für Plattform- und Mandanten-Nutzer: `src/server/mfa.ts`; Policy-Flag `securityPolicy.mfaRequired` existiert. +- **Passwort**: `src/lib/password-policy.ts` (Validierung) + `src/server/password.ts` (Argon2id + Generator); **Force-Change**-Gate im `(app)`-Layout. +- **Auth**: zwei NextAuth-Instanzen — Mandant `src/server/auth.ts` (`/login`), Plattform `src/server/platform-auth.ts` (`/platform/login`). **`PlatformAdmin`**-Store getrennt. +- **Queue**: BullMQ + Redis im Stack. **Audit-Log** mit `tenantId` nullable (`scope=platform`). **Task/TaskComment** für Ticket-/Freigabe-Ereignisse. +- **Modul-Guard**: neue Server-Actions in `scripts/check-module-guards.ts` eintragen; tenant-Modelle in `TENANT_MODELS`+RLS. + +## Betriebs-/DNS-Voraussetzungen (kein Code, aber Vorbedingung) +Dedizierte Absenderdomain (`no-reply@certvia.de`) mit **SPF, DKIM, DMARC**; TLS/HSTS; SMTP-Zugangsdaten + alle Secrets aus **Env/Secret-Store** (nicht im Repo). + +--- + +## Reihenfolge (sequenziell, 1 Entwickler) +SEC1 → SEC2 → SEC3 → SEC4 → SEC5 → SEC6. Einzelne P0-Härtungen (Rate-Limit an Login/Reset/MFA, Token-Hashing) landen **inline** in SEC2/SEC3; die globalen Härtungen bündelt SEC5. + +--- + +## SEC1 — SMTP-Mail-Fundament (`dev/sec1-mail-smtp`) [L] +**Ziel:** zuverlässiger, gebrandeter, asynchroner Mail-Versand als Fundament für Reset/Einladung/Benachrichtigung. +- **Mail-Service** `src/server/mail/**` mit **SMTP-Transport** (nodemailer, TLS) hinter einem Interface `sendMail(template, to, vars, locale)` — Provider später austauschbar. +- **Queue/Worker** über BullMQ/Redis: asynchron, **Retry mit Backoff**, Dead-Letter, Rate-Limit; Fehler/Bounce ins Log. +- **Templates** (Certvia-gebrandet, **de/en**, HTML + Text-Alternative): Einladung, Passwort-Reset, „Passwort geändert", E-Mail-Änderung bestätigen, „MFA geändert", **Ticket-/Freigabe-/Fristen-Benachrichtigung**. +- **Benachrichtigungsregeln**: je Nutzer/Ereignis opt-in/opt-out + Sprache; strikt mandantengetrennt. Trigger aus Task-Ereignissen (Zuweisung, Freigabe-Anfrage, Entscheidung, Fälligkeit). +- **Admin-Testversand** (eine Aktion „Test-Mail senden") zur Zustellprüfung. +- **AK:** Mail wird asynchron mit Retry versendet; Templates gebrandet + zweisprachig; Bounces/Fehler geloggt; Ticket-Benachrichtigung wird bei Task-Zuweisung/Freigabe ausgelöst; keine Secrets im Repo. + +## SEC2 — Passwort-Self-Service & Sessions (`dev/sec2-auth-selfservice`) [M–L] · Abh. SEC1 +- **Passwort-Reset**: „Passwort vergessen" → **Single-Use-Token**, kurzlebig (30–60 Min), **serverseitig gehasht** gespeichert, an E-Mail gebunden. **Enumeration-Schutz** (immer gleiche Antwort), **Rate-Limit** je IP/Konto. Nach Reset: **alle Sessions invalidieren** + Bestätigungs-Mail + Audit; deaktivierte/gesperrte Konten erhalten keinen Reset. +- **Passwort selbst ändern**: Profilseite mit **Alt-Passwort-Bestätigung**, Policy-Prüfung, danach **andere Sessions abmelden** (aktuelle behalten), Bestätigungs-Mail + Audit. +- **E-Mail-Änderung**: **Double-Opt-in** an neue Adresse + Benachrichtigung an alte; Audit. +- **Session-Invalidierung** als wiederverwendbarer Baustein (bei Reset/Änderung/Deaktivierung/MFA-Änderung). +- **AK:** Reset-Token single-use/gehasht/rate-limited/enumeration-safe; Self-Change funktioniert; E-Mail-Änderung verifiziert; Sessions werden korrekt invalidiert; alle Ereignisse im Audit. + +## SEC3 — MFA pro Tenant erzwingen + Passkeys (`dev/sec3-mfa-passkeys`) [L] · Abh. SEC1 +- **Optional bleibt Default.** Im **Adminportal** kann pro Mandant `securityPolicy.mfaRequired` gesetzt werden (Superadmin) → **Enrollment-Gate**: Nutzer dieses Mandanten werden beim nächsten Login zur MFA-Einrichtung gezwungen (analog Force-Change-Gate im `(app)`-Layout). Ebenso erzwingbar für **alle Plattform-Admins**. +- **Passkeys/WebAuthn** als zusätzlicher 2. Faktor (`@simplewebauthn/server` + Browser-API): Registrierung + Login; Nutzer kann **TOTP oder Passkey** verwenden; Credentials verwaltbar (anlegen/entfernen). +- **Step-up-Re-Auth** für sensible Aktionen: MFA deaktivieren, Plattform-Admin anlegen, Datenexport, Mandant löschen. +- **TOTP-Secret at rest verschlüsselt** (falls noch Klartext) + **Rate-Limit** auf Code-Eingabe; Recovery-Codes-Flow (Anzeige/Regenerierung, Verbrauch protokolliert) abrunden. +- **AK:** Admin setzt `mfaRequired` je Tenant → betroffene Nutzer müssen beim Login enrollen; Passkey-Registrierung + -Login funktionieren; Step-up greift bei sensiblen Aktionen; TOTP-Secret verschlüsselt; MFA global weiterhin optional, wenn Policy es nicht verlangt. + +## SEC4 — Plattform-Admin-Verwaltung (`dev/sec4-platform-admins`) [M] · Abh. SEC1, SEC3 +- **Verwaltungs-UI** im Adminportal (`src/app/(platform)/admin/**`, Actions `platform*.ts`): weitere **`PlatformAdmin`** anlegen (Einladung via SEC1 oder Initial-Passwort), **Rollen** (z. B. „Voll-Admin" vs. „Support/Read-only"), **sperren/reaktivieren**, Passwort-Reset, **MFA-Pflicht** für Plattform-Admins. +- **Selbst-Aussperr-Schutz** auf Plattform-Ebene (letzter Voll-Admin nicht entfernbar/deaktivierbar); kritische Aktionen mit **Step-up** (SEC3). +- **Vollständiges Plattform-Audit** (`scope=platform`) jeder Aktion. +- **AK:** ein zweiter Voll-Admin ist anlegbar und kann verwalten; Rollen greifen (Read-only kann nichts ändern); Last-Admin-Schutz aktiv; jede Aktion protokolliert. + +## SEC5 — Härtung P0 (quer) (`dev/sec5-hardening`) [M] +- **HTTP-Security-Header** (zentrale Middleware): CSP, HSTS, `X-Frame-Options`/`frame-ancestors`, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`. +- **Rate-Limiting/Brute-Force** global an Login/Reset/MFA/Admin-Aktionen (IP **und** kontobezogen), ergänzt den bestehenden Konto-Lockout. +- **Security-Audit erweitern**: Logins (Erfolg/Fehlschlag), Rechte-/Rollenänderungen, MFA-Änderungen, Exporte, Admin-Aktionen; **append-only**/manipulationssicher; Aufbewahrung definiert. +- **Passwort-Breach-Check** (HaveIBeenPwned k-Anonymity) beim Setzen/Ändern zusätzlich zur Policy. +- **Token-/Secret-Hygiene**: alle Tokens single-use + gehasht (Konsistenz zu SEC2/SEC3); **Secret-Scanning** in CI. +- **AK:** Header messbar gesetzt (z. B. securityheaders-Check); Rate-Limits greifen; Audit-Ereignisse vorhanden; bekannte kompromittierte Passwörter werden abgelehnt. + +## SEC6 — DSGVO-Funktionen (`dev/sec6-dsgvo`) [L] · Abh. SEC1, SEC3 (Step-up) +- **Mandanten-Datenexport** (vollständig, maschinenlesbar, z. B. JSON/ZIP), Admin-getriggert, **asynchron** via Queue, Download-Link mit Ablauf. +- **Löschung/Retention**: Mandanten-Löschung (Soft→Hard mit Karenz), **Aufbewahrungsfristen**/Löschkonzept, RLS-bewusste Kaskaden; Audit; Step-up-Bestätigung. +- **Betroffenenrechte**: Export/Löschung nutzerbezogener Daten, soweit anwendbar. +- **Doku-Bausteine** (Inhalt, kein Code): AVV/DPA + TOMs — als offener fachlicher Punkt markieren. +- **AK:** vollständiger Tenant-Export erzeugbar; Löschung respektiert Retention + Audit + Step-up; DSGVO-Aktionen protokolliert. + +--- + +## Definition of Done (jede Story) +`npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check) grün · neue Actions in `check-module-guards.ts` · neue tenant-Modelle in `TENANT_MODELS`+RLS+Migration (RLS-DO-Block) · Security-Verifikation (Header/Rate-Limit/Token) · Browser-Test der Flows · Demo-Umgebung lauffähig · **Secrets nur aus Env**. + +## Hot Files (koordiniert, da 1 Entwickler → nur Reihenfolge beachten) +`prisma/schema.prisma` + Migrationsreihenfolge · zentrale **Middleware** (Header/Rate-Limit) · `(app)`- und `(platform)`-Layouts (Enrollment-/Force-Gates) · `src/server/auth.ts` / `platform-auth.ts` / `mfa.ts` · `scripts/check-module-guards.ts`. + +## Offene fachliche Punkte +- DNS: SPF/DKIM/DMARC vor Produktivversand aktiv. +- AVV/DPA-Texte + TOMs (Datenschutz/ISB). +- Aufbewahrungsfristen je Datenart festlegen (Grundlage für SEC6-Retention). diff --git a/docs/sicherheit/README.md b/docs/sicherheit/README.md new file mode 100644 index 0000000..bee3aa8 --- /dev/null +++ b/docs/sicherheit/README.md @@ -0,0 +1,19 @@ +# Sicherheit & Administration — Übergabepaket + +## Inhalt / Reihenfolge +1. **Sicherheit-und-Administration-Konzept.md** — PO-Konzept: Ist-Abgleich, Empfehlungen, Roadmap. +2. **Aufgabenpaket-Sicherheit-Administration.md** — Ein-Entwickler-Backlog SEC1–SEC6 (Branches `dev/sec<n>-…`). +3. **SEC1-Mail-Fundament-Detail.md** — ausgearbeiteter Prompt: SMTP-Mail (Fundament). +4. **SEC2-Auth-SelfService-Detail.md** — ausgearbeiteter Prompt: Passwort-Reset, Passwort ändern, E-Mail-Änderung, Session-Invalidierung. + +## Fixierte Entscheidungen +- Mail via **SMTP** (nodemailer) im ersten Schritt. +- **1 Entwickler**, sequenziell: SEC1 → SEC2 → SEC3 → SEC4 → SEC5 → SEC6. +- **2FA optional**, aber pro Tenant im **Adminportal** als Pflicht (`mfaRequired`) erzwingbar; **Passkeys** dabei. +- **DSGVO-Funktionen** enthalten. + +## Naht SEC1 ↔ SEC2 +SEC1 liefert Versand + Templates; **SEC2 erzeugt die Tokens** (single-use, gehasht) und übergibt SEC1 nur die fertige `actionUrl` — keine Klartext-Secrets im MailLog. + +## Start +Mit **SEC1** beginnen, dann **SEC2**. DNS-Vorbedingung: SPF/DKIM/DMARC vor Produktivversand. Secrets nur aus Env/Secret-Store. diff --git a/docs/sicherheit/SEC1-Mail-Fundament-Detail.md b/docs/sicherheit/SEC1-Mail-Fundament-Detail.md new file mode 100644 index 0000000..33527d9 --- /dev/null +++ b/docs/sicherheit/SEC1-Mail-Fundament-Detail.md @@ -0,0 +1,125 @@ +# SEC1 — SMTP-Mail-Fundament (Detail-Prompt) + +> Claude-Code-Prompt für **einen** Entwickler. Basis `dev` → Branch **`dev/sec1-mail-smtp`** (PR-Ziel `dev`). +> Ziel: zuverlässiger, gebrandeter, **asynchroner** Mail-Versand über **SMTP** — Fundament für Passwort-Reset (SEC2), Einladung, MFA-Hinweise (SEC3) und Ticket-/Freigabe-/Fristen-Benachrichtigungen. Stack vorhanden: **BullMQ + Redis**, Next.js/TS, Prisma, i18n (de/en), Task/TaskComment, Audit-Log, `TenantSettings`. + +--- + +## 1. Architektur (Zielbild) + +``` +Aufrufer (Action/Event) Worker-Prozess + │ enqueueMail({template,to, ┌───────────────────────────┐ + │ locale,vars,tenantId}) │ BullMQ "mail"-Queue │ + ▼ │ → render(template,locale) │ +MailService ──push job──► Redis ───────► │ → MailProvider.send() │ + │ │ → MailLog(status) │ + └─ MailLog(pending) │ → Retry/Backoff/DLQ │ + └───────────────────────────┘ +Provider-Interface ← SMTP-Impl (nodemailer) [später austauschbar] +``` + +Trennung in vier Schichten: **Provider** (SMTP), **Templates** (Render), **Queue/Worker** (Zustellung + Retry), **Service/Trigger** (Aufruf + Regeln + Log). + +--- + +## 2. Datenmodelle (Prisma, mit Migration + RLS) + +- **`MailLog`** (Auditierbarkeit + Idempotenz): `id`, `tenantId` (nullable → Plattform-Mails), `to`, `template`, `locale`, `status` (`pending|sent|failed|bounced|suppressed`), `providerMessageId?`, `error?`, `dedupeKey?` (unique, für Idempotenz), `createdAt`, `sentAt?`. → in `TENANT_MODELS`+RLS (Plattform-Zeilen mit `tenantId=null`, `scope=platform`). +- **`NotificationPreference`**: `userId`, `eventType`, `email` (bool, default true), `locale?`. Default = opt-in; UI kommt später — jetzt Modell + Default-Auflösung. +- Migrationen im Prisma-7-Flow (RLS-DO-Block manuell anhängen). + +--- + +## 3. Konfiguration (Env / Secret-Store — nichts ins Repo) + +`SMTP_HOST`, `SMTP_PORT`, `SMTP_SECURE` (true=TLS/465, false=STARTTLS/587), `SMTP_USER`, `SMTP_PASS`, `MAIL_FROM` (`no-reply@certvia.de`), `MAIL_FROM_NAME` (`Certvia`), `APP_BASE_URL`, `MAIL_REPLY_TO?`. +- **Boot-Validierung** (z. B. zod): fehlt Konfig → klarer Fehler, Versand deaktiviert (Jobs bleiben `pending`, Warnung im Log). Kein stiller Fehlversand. + +--- + +## 4. Provider & Service + +- **Interface** `src/server/mail/provider.ts`: `send(msg: {from,to,replyTo?,subject,html,text,headers?}): Promise<{messageId}>`. So bleibt der Provider austauschbar (heute SMTP, später API). +- **SMTP-Impl** `src/server/mail/provider-smtp.ts`: **nodemailer** (Pool, TLS, Timeouts). Verbindung wiederverwenden. +- **Service** `src/server/mail/service.ts`: + - `enqueueMail(input)` → `dedupeKey` bilden (z. B. `template:to:refId`), `MailLog(pending)` anlegen (unique verhindert Doppelversand), Job in Queue. + - `renderMail(template, locale, vars)` → `{subject, html, text}` (Abschnitt 5). + - Action-Datei in `scripts/check-module-guards.ts` als **`EXEMPT`** eintragen (Infrastruktur, kein gegatetes Modul). + +--- + +## 5. Templates (gebrandet, de/en, HTML + Text) + +- **Basis-Layout** `src/server/mail/templates/_layout.*`: Certvia-Kopf (Logo/Wortmarke), Markenfarben (Violett `#5d52a3` / Magenta-Akzent `#812d80`), **Inline-CSS** (E-Mail-Client-tauglich; MJML oder handgepflegtes Table-Layout), Fußzeile „**Certvia — ein Produkt von GEFIM**" + Impressum/Abmelde-Hinweis. Immer **Text-Alternative** mitliefern. +- **i18n:** je Template `de`/`en` über die bestehenden Message-Kataloge; `locale` aus Nutzer/`NotificationPreference`, Fallback `de`. +- **Template-Set (Erststufe):** + +| Template-Key | Anlass | Kern-Variablen | Auslöser | +|---|---|---|---| +| `invitation` | Nutzer-Onboarding | `name, tenantName, actionUrl, expires` | SEC1/SEC4 (Einladung) | +| `password_reset` | Reset angefordert | `name, actionUrl, expires` | **SEC2** (Token wird dort erzeugt) | +| `password_changed` | Passwort geändert | `name, when, ip?` | SEC2 | +| `email_change_verify` | E-Mail-Änderung bestätigen | `name, actionUrl, expires` | SEC2 | +| `mfa_changed` | MFA aktiviert/deaktiviert/Recovery neu | `name, change, when` | SEC3 | +| `notification` | Ticket/Freigabe/Fälligkeit | `name, subject, body, actionUrl, taskType` | Task-Events (Abschnitt 6) | + +> **Wichtig:** Reset-/Verify-/Einladungs-**Tokens** werden von SEC2/SEC3/SEC4 erzeugt (single-use, gehasht). SEC1 liefert nur Template + Versand und bekommt die fertige `actionUrl` als Variable — **keine** Klartext-Secrets ins MailLog/Log schreiben. + +--- + +## 6. Benachrichtigungs-Trigger (Ticket-/Freigabe-/Fristen) + +- **Task-Ereignisse** (bestehendes `Task`/`TaskComment` + `submitForApproval`): bei **Zuweisung**, **Freigabe-Anfrage**, **Freigabe-Entscheidung** (angenommen/abgelehnt) → `notification`-Mail an den jeweils Zuständigen, sofern `NotificationPreference.email` aktiv. +- **Fristen-Erinnerung:** **BullMQ Repeatable Job** (z. B. täglich) prüft fällige/überfällige Aufgaben (`dueDate`) und versendet gebündelte Erinnerungen (keine Spam-Schleifen — je Aufgabe max. definierte Frequenz, `dedupeKey`). +- Alle Trigger **mandantenisoliert**; Sprache je Empfänger. + +--- + +## 7. Queue / Worker / Robustheit + +- **Queue** `mail` (BullMQ). **Worker** `src/server/mail/worker.ts`: `render → provider.send → MailLog(sent|failed)`. +- **Retry:** z. B. 5 Versuche, exponentielles Backoff; nach Ausschöpfung `status=failed` + **Dead-Letter** (separate Queue/Flag) + Alarm-Logeintrag. +- **Rate-Limit** je Empfänger/Domain (BullMQ Limiter), **Concurrency** begrenzt, **Graceful Shutdown**. +- **Idempotenz:** `dedupeKey`-Unique + „bereits gesendet"-Kurzschluss. +- **Betriebsmodus dokumentieren:** Worker als eigener Prozess (Coolify) **oder** im App-Container gestartet — entscheiden und im README festhalten. + +--- + +## 8. Sicherheit / Datenschutz + +- **TLS erzwingen** (STARTTLS/implicit), Zertifikatsprüfung an. Secrets nur aus Env/Secret-Store. +- **Keine sensiblen Inhalte** in Mails über das Nötige hinaus; **keine Tokens** in Logs/MailLog (nur `dedupeKey`/`providerMessageId`). +- **Abmelde-/Präferenz-Hinweis** in Benachrichtigungs-Mails (nicht in sicherheitskritischen Transaktionsmails wie Reset). +- **Enumeration-Schutz** ist Sache von SEC2 (Reset) — SEC1 versendet nur, was ihm übergeben wird. +- **Audit:** Versandereignisse (ohne Inhalt) ins Security-Audit (Erweiterung in SEC5 kompatibel halten). +- **DNS-Vorbedingung:** SPF, DKIM, DMARC für die Absenderdomain (Ops; vor Produktivversand). + +--- + +## 9. Admin-Testversand +- Aktion „Test-Mail senden" im Adminportal (an eigene Adresse), zeigt Ergebnis/MailLog-Status → schnelle Zustell-/DKIM-Prüfung. + +--- + +## 10. Akzeptanzkriterien +- `enqueueMail(...)` legt `MailLog(pending)` an und stellt asynchron über SMTP zu; bei Erfolg `sent` + `providerMessageId`, bei Fehler Retry→`failed`/DLQ. +- Templates rendern **de und en**, HTML **und** Text, mit Certvia-Branding und „ein Produkt von GEFIM". +- **Ticket-Benachrichtigung** wird bei Task-Zuweisung/Freigabe ausgelöst und respektiert `NotificationPreference` + Mandantenisolation. +- **Fristen-Erinnerung** läuft als wiederkehrender Job ohne Doppelversand. +- Fehlende SMTP-Konfig → klarer Fehler, kein stiller Fehlversand; keine Secrets/Tokens im Repo oder Log. +- Lokaler Test gegen **Mailpit/Mailhog** dokumentiert; Admin-Testversand funktioniert. + +## 11. Definition of Done +`npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check) grün · Mail-Action als `EXEMPT` registriert · `MailLog`/`NotificationPreference` in `TENANT_MODELS`+RLS+Migration (RLS-DO-Block) · Worker-Betriebsmodus im README · lokaler Mailpit-Testnachweis (Screenshots) · Demo-Umgebung lauffähig. + +## 12. Testplan (Kurz) +1. **Lokal Mailpit** (`docker run mailpit`) als SMTP-Ziel; Env setzen; Test-Mail senden → in Mailpit sichtbar (HTML+Text, de/en). +2. **Retry:** Provider künstlich fehlschlagen lassen → Job retryt, landet nach N Versuchen in DLQ, `MailLog=failed`. +3. **Idempotenz:** zweimal gleicher `dedupeKey` → nur eine Mail. +4. **Trigger:** Aufgabe zuweisen / Freigabe anfragen → `notification`-Mail; `NotificationPreference.email=false` → keine Mail. +5. **Fristen-Job:** überfällige Aufgabe → genau eine Erinnerung je Zyklus. + +## 13. Bibliotheken +`nodemailer` (SMTP) · `bullmq` (vorhanden) · optional `mjml` für Template-Rendering · `zod` (Env-Validierung, i. d. R. vorhanden). +Nächste Pakete bauen darauf auf: **SEC2** (Reset/Change nutzen `password_reset`/`password_changed`/`email_change_verify`), **SEC3** (`mfa_changed`), **SEC4** (`invitation`). diff --git a/docs/sicherheit/SEC2-Auth-SelfService-Detail.md b/docs/sicherheit/SEC2-Auth-SelfService-Detail.md new file mode 100644 index 0000000..b438aad --- /dev/null +++ b/docs/sicherheit/SEC2-Auth-SelfService-Detail.md @@ -0,0 +1,100 @@ +# SEC2 — Passwort-Reset, Passwort ändern, E-Mail-Änderung & Sessions (Detail-Prompt) + +> Claude-Code-Prompt für **einen** Entwickler. Basis `dev` → Branch **`dev/sec2-auth-selfservice`** (PR-Ziel `dev`). **Abhängigkeit: SEC1** (Mail-Templates `password_reset`, `password_changed`, `email_change_verify`). +> Ziel: sicherer **Self-Service** — Passwort vergessen/zurücksetzen, Passwort selbst ändern, E-Mail-Adresse ändern (verifiziert) — plus ein wiederverwendbarer **Session-Invalidierungs-Baustein**. Gilt für **Mandanten-Nutzer** (`/login`) **und Plattform-Admins** (`/platform/login`). + +## Vorhandenes wiederverwenden +- `src/lib/password-policy.ts` (Validierung, client-safe) + `src/server/password.ts` (**Argon2id** + Generator). **Nicht** neu implementieren. +- Zwei NextAuth-Instanzen: `src/server/auth.ts` (Mandant) · `src/server/platform-auth.ts` (Plattform). **Force-Change-Gate** im `(app)`-Layout als Muster. +- Konto-**Lockout** (Tenant) + `User.mustChangePassword` vorhanden. Audit-Log (`scope=platform` für Plattform-Ereignisse). SEC1-Mailservice (`enqueueMail`). + +--- + +## 1. Token-Modell (single-use, gehasht) + +**`AuthToken`** (eigenes Modell, nicht im JWT): +`id`, `principalType` (`tenant_user` | `platform_admin`), `principalId`, `tenantId?` (nur bei tenant_user, für RLS), `type` (`password_reset` | `email_change`), `tokenHash` (SHA-256 des Rohtokens), `newEmail?` (nur bei email_change), `expiresAt`, `usedAt?`, `createdAt`, `requestIp?`. +- **Roh-Token** = 32 Byte CSPRNG, base64url; nur im **Link** (nie in DB/Log). In DB nur der **Hash**. Lookup per Hash, **konstante-Zeit**-Vergleich. +- **Gültigkeit** kurz (Reset 30–60 Min, E-Mail-Verify 60 Min); **single-use** (`usedAt` setzen); alte offene Tokens desselben Typs beim Neuanfordern invalidieren. +- tenant_user-Zeilen unter RLS (`tenantId`); platform_admin-Zeilen `tenantId=null` (`scope=platform`). Migration + RLS-DO-Block. + +--- + +## 2. Passwort-Reset (Self-Service) + +**2a Anfrage** — „Passwort vergessen?" auf `/login` **und** `/platform/login`: +- Eingabe E-Mail → **immer gleiche Antwort** („Falls ein Konto existiert, wurde eine E-Mail gesendet."). **Kein** Rückschluss auf Existenz (Enumeration-Schutz). +- **Rate-Limit**: je IP **und** je Konto (z. B. 5/Stunde); zusätzlich globaler Missbrauchsschutz. +- Existiert das Konto **und** ist aktiv/nicht gesperrt: `AuthToken(password_reset)` erzeugen, Link `"{APP_BASE_URL}/reset?token=…"` per SEC1 (`password_reset`) senden. **Deaktivierte/gesperrte** Konten: keine Mail, keine Fehlermeldung. + +**2b Einlösung** — `/reset?token=…`: +- Token per Hash validieren (existiert, nicht abgelaufen, nicht benutzt, Konto aktiv). Ungültig → generische Meldung + Angebot „neu anfordern". +- Neues Passwort setzen: **Policy-Prüfung** (`password-policy.ts`) + Argon2id (`password.ts`). Bei Wiederverwendung: **Breach-Check-Hook** vorsehen (Implementierung in SEC5). +- Danach: `usedAt` setzen, **alle Sessions invalidieren** (Abschnitt 5), `mustChangePassword=false`, **Bestätigungs-Mail** (`password_changed`), **Audit**-Eintrag (ohne Token). +- Redirect zum passenden Login (`/login` bzw. `/platform/login`). + +--- + +## 3. Passwort selbst ändern + +Profilseite (Mandanten-App **und** Plattform-Profil): +- Felder: aktuelles Passwort, neues, Wiederholung. **Alt-Passwort verifizieren** (Argon2id), Policy-Prüfung. +- Erfolg: Passwort setzen, **andere Sessions abmelden** (aktuelle behalten — Abschnitt 5), Bestätigungs-Mail (`password_changed`), Audit. +- Fehler generisch; Rate-Limit auf Alt-Passwort-Versuche. + +--- + +## 4. E-Mail-Adresse ändern (verifiziert, Double-Opt-in) + +- Nutzer gibt neue Adresse ein → **Alt-Passwort bestätigen** (Step-up folgt in SEC3). Prüfen, dass die neue Adresse **frei** ist (mandantenweit bzw. plattformweit), ohne Enumeration nach außen. +- `AuthToken(email_change, newEmail)` erzeugen; **Verifizierungslink an die NEUE Adresse** (`email_change_verify`). +- Klick auf Link: Token validieren → E-Mail aktualisieren, `usedAt` setzen; **Benachrichtigung an die ALTE Adresse** („Ihre E-Mail wurde geändert"); Audit. Login-Identität konsistent halten (E-Mail ist Login). +- Kollisionsfall (Adresse zwischenzeitlich vergeben): sauber ablehnen. + +--- + +## 5. Session-Invalidierung (wiederverwendbarer Baustein) + +NextAuth v5 nutzt **JWT (stateless)** → globale Invalidierung über eine **Versionsmarke**: +- Feld **`sessionsValidAfter`** (Timestamp) bzw. `tokenVersion` an `User` **und** `PlatformAdmin`. +- JWT trägt `iat`/Version; im **Auth-Callback bzw. Layout-Check** (die DB wird ohnehin schon für Kontostatus/`mustChangePassword` geprüft) zusätzlich `sessionsValidAfter` vergleichen → ältere Tokens sind ungültig → Abmeldung. +- **Bump-Auslöser:** Passwort-Reset (2b), Passwort ändern (3, andere Sessions), Konto-Deaktivierung, MFA-Änderung (SEC3), E-Mail-Änderung. +- **„Aktuelle Session behalten"** (bei Self-Change): nach Bump das **aktuelle** JWT mit neuer Version neu ausstellen. +- **AK:** ein Bump macht bestehende Sessions serverseitig ungültig; Self-Change meldet **nur** die anderen ab. +- *Optionaler Folgeschritt (nicht SEC2-Pflicht):* „aktive Sitzungen anzeigen + einzeln abmelden" braucht Session-Records — als P1 vermerken. + +--- + +## 6. Sicherheit (verbindlich) +- Tokens: CSPRNG, **nur gehasht** gespeichert, single-use, kurzlebig, konstante-Zeit-Vergleich; **nie** in Logs/MailLog. +- **Enumeration-Schutz** überall (Reset, E-Mail-Änderung): generische, einheitliche Antworten und Timing. +- **Rate-Limiting** an Reset-Anfrage, Reset-Einlösung, Alt-Passwort-Prüfung (IP + Konto) — bindet an den globalen Limiter aus SEC5, hier aber schon inline scharf. +- Reset/Änderung an **gesperrten/deaktivierten** Konten unmöglich. +- Alle Ereignisse ins **Audit** (wer/wann/was, ohne Secrets); kompatibel zur SEC5-Audit-Erweiterung. +- Kein Auto-Login direkt nach Reset (Nutzer meldet sich neu an) — reduziert Token-Missbrauch. + +--- + +## 7. Akzeptanzkriterien +- „Passwort vergessen" auf `/login` **und** `/platform/login` erzeugt (nur bei aktivem Konto) eine Reset-Mail; Antwort ist **immer** enumeration-neutral; Rate-Limit greift. +- Reset-Link ist **single-use**, abgelaufen/benutzt → generische Ablehnung; nach Reset sind **alle Sessions ungültig**, Bestätigungs-Mail + Audit vorhanden. +- Passwort-Selbständerung mit Alt-Passwort-Prüfung + Policy; **andere** Sessions werden abgemeldet, aktuelle bleibt. +- E-Mail-Änderung erst nach **Verifizierung der neuen Adresse** wirksam; **alte Adresse** wird informiert. +- Token-Hashes in DB (keine Klartext-Tokens), keine Secrets in Logs. +- Funktioniert für Mandanten-Nutzer **und** Plattform-Admins. + +## 8. Definition of Done +`tsc` → `lint` → `build` (Guard-Check) grün · neue Actions in `check-module-guards.ts` · `AuthToken` + `sessionsValidAfter`-Felder in Migration (+RLS-DO-Block, `AuthToken` in `TENANT_MODELS` für tenant-Zeilen) · Browser-Test aller Flows (Tenant + Plattform) gegen Mailpit · Demo-Umgebung lauffähig. + +## 9. Testplan (Kurz) +1. **Reset happy path** (Tenant + Plattform): Anfrage → Mail (Mailpit) → Link → neues Passwort → alte Sessions abgemeldet → Login neu. +2. **Enumeration:** unbekannte E-Mail → identische Antwort/Timing, keine Mail. +3. **Token-Missbrauch:** abgelaufen / bereits benutzt / manipuliert → generische Ablehnung. +4. **Rate-Limit:** viele Anfragen → gedrosselt. +5. **Self-Change:** falsches Alt-Passwort → Ablehnung; korrekt → andere Session (zweiter Browser) wird ungültig, aktuelle bleibt. +6. **E-Mail-Änderung:** Verify-Link an neue Adresse nötig; alte Adresse erhält Hinweis; unbestätigt → keine Änderung. +7. **Deaktiviertes Konto:** kein Reset möglich. + +## 10. Bibliotheken / Bausteine +`crypto` (CSPRNG/SHA-256, konstante-Zeit) · vorhandene `password-policy.ts`/`password.ts` · SEC1-`enqueueMail` · Rate-Limit-Util (mit SEC5 teilen). +Folgepaket **SEC3** nutzt den Session-Invalidierungs-Baustein (MFA-Änderung) und ergänzt **Step-up-Re-Auth** für die E-Mail-Änderung/kritische Aktionen. diff --git a/docs/sicherheit/Sicherheit-und-Administration-Konzept.md b/docs/sicherheit/Sicherheit-und-Administration-Konzept.md new file mode 100644 index 0000000..fee898b --- /dev/null +++ b/docs/sicherheit/Sicherheit-und-Administration-Konzept.md @@ -0,0 +1,105 @@ +# Sicherheit & Administration — Konzept & Empfehlung (PO) + +Grundlage: `STAND-dev-branch.md` (Ist-Stand `dev`). Ziel: die genannten Punkte umsetzen **und** — weil Certvia selbst ein ISMS-Produkt ist — ein Sicherheitsniveau erreichen, das man dem Kunden vorlebt („eat your own dog food"). Status-Legende: ✅ vorhanden · 🟡 teilweise · 🟥 neu. + +--- + +## 1. Eure Punkte im Ist-Abgleich (wichtig: nicht doppelt bauen) + +| Anforderung | Status heute | Was fehlt / zu tun | +|---|---|---| +| **E-Mail-Versand** (Onboarding, Reset, Ticket-/Fristen-Benachrichtigungen) | 🟥 offen | „Paket 4" bewusst zurückgestellt; Aktivierung ist bereits **gekapselt**. Kompletter SMTP-/Mail-Layer + Templates neu. | +| **Passwort-Reset** | 🟥 offen | Hängt am Mail-Versand; aktuell nur Initial-/Einmal-Passwort. Self-Service-Reset via signiertem, kurzlebigem Token neu. | +| **Passwort ändern (selbst)** | 🟡 teilweise | **Force-Change** (`/change-password`) + Passwort-Policy (Argon2id) vorhanden. **Freiwillige** Änderung im Profil ergänzen (mit Alt-Passwort-Bestätigung). | +| **2FA / MFA** | 🟡 teilweise | **TOTP optional** (Plattform-Admins *und* Mandanten-Nutzer) + Recovery-Codes vorhanden; Policy-Flag `mfaRequired` da. **Fehlt:** Enrollment-**Erzwingung** beim Login (Gate), optional WebAuthn/Passkeys. | +| **Weiterer übergreifender Admin im Adminportal** | 🟡 teilweise | Getrennter **`PlatformAdmin`-Store** + eigener Login (`/platform/login`) + MFA existiert. **Fehlt:** CRUD-UI im Adminportal, um **weitere Plattform-Admins** anzulegen/zu verwalten (Rollen, Sperren, Reset, MFA-Pflicht). | + +**Kernbotschaft:** 2FA und der getrennte Superadmin-Store sind **im Kern schon da** — hier geht es um *Erzwingung* bzw. *Verwaltungs-UI*, nicht um Neubau. Der echte Neubau ist der **Mail-Layer** (und alles, was daran hängt: Reset, Einladung, Benachrichtigungen). + +--- + +## 2. Bausteine für die genannten Punkte + +### 2.1 E-Mail-Infrastruktur (Fundament — schaltet Reset/Einladung/Benachrichtigung frei) 🟥 +- **Transaktionaler Mail-Provider** (SMTP oder API): z. B. Postmark/SendGrid/Mailgun/Amazon SES **oder** eigener SMTP. Auswahl = offene Entscheidung (§5). +- **Domänen-Authentifizierung**: **SPF, DKIM, DMARC** einrichten (sonst Spam/Spoofing). Dediziert Absender-Domain (z. B. `no-reply@certvia.de`). +- **Template-Engine** (gebrandet, Certvia): Layout-Basis + Bausteine für Einladung, Passwort-Reset, Passwort-geändert-Bestätigung, MFA-Änderung, Ticket-/Freigabe-/Fristen-Benachrichtigung. +- **Queue + Retry** (BullMQ/Redis ist im Stack) für zuverlässigen, asynchronen Versand; Fehler-/Bounce-Handling; Rate-Limit. +- **Benachrichtigungsregeln** je Nutzer/Ereignis (opt-in/opt-out, Sprache de/en), respektiert Mandanten-Isolation. + +### 2.2 Passwort-Reset (Self-Service) 🟥 +- **Single-Use-Token**, **kurzlebig** (z. B. 30–60 Min), **serverseitig gehasht** gespeichert (nicht im Klartext), an E-Mail gebunden. +- **Enumeration-Schutz**: „Falls ein Konto existiert, wurde eine E-Mail gesendet." (immer gleiche Antwort), **Rate-Limit** pro IP/Konto. +- Nach Reset: **alle Sessions invalidieren**, Bestätigungs-Mail „Passwort geändert", Audit-Log-Eintrag. Deaktivierte/geblockte Konten: kein Reset. + +### 2.3 Passwort selbst ändern 🟡 +- Profilseite „Passwort ändern": **Alt-Passwort-Bestätigung**, Policy-Prüfung (bestehende `password-policy.ts`), danach **andere Sessions abmelden** (aktuelle behalten), Bestätigungs-Mail + Audit. + +### 2.4 2FA scharfschalten & härten 🟡→ +- **MFA-Enrollment-Gate**: bei `securityPolicy.mfaRequired` (tenant-weit) oder für Plattform-Admins Enrollment beim Login **erzwingen** (analog Force-Change-Gate). +- **Recovery-Codes**: Anzeige/Regenerierung, Verbrauch protokolliert (vorhanden — Flow abrunden). +- **Optional/Ausbau**: **WebAuthn/Passkeys** (phishing-resistent) als 2. Faktor; **Re-Auth** (Step-up) für sensible Aktionen (MFA deaktivieren, Admin anlegen, Export). +- **TOTP-Secret** at rest **verschlüsselt** speichern (falls noch Klartext) + Rate-Limit auf Code-Eingabe. + +### 2.5 Weiterer übergreifender Plattform-Admin 🟡→ +- **Plattform-Admin-Verwaltung** im Adminportal (`/platform/...`): Liste, **anlegen** (Initial-Passwort/Einladung), Rollen/Rechte (z. B. „Voll-Admin" vs. „Support/Read-only"), **sperren/reaktivieren**, Passwort-Reset, **MFA-Pflicht für alle Plattform-Admins**. +- **Vier-Augen für kritische Plattform-Aktionen** (mind. 2 Admins, kein Self-Lockout — der Lockout-Schutz existiert bereits für Tenant-Rollen, hier fürs Plattform-Level ergänzen). +- **Vollständiges Audit** jeder Plattform-Admin-Aktion (`scope=platform`, ist im Log-Modell vorgesehen). + +--- + +## 3. Weitere sinnvolle Sicherheitsmaßnahmen (Empfehlung, priorisiert) + +**P0 — sollte mit diesem Block kommen (hoher Nutzen, moderat):** +- **HTTP-Security-Header**: CSP, HSTS, `X-Frame-Options`/`frame-ancestors`, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`. (Zentraler Middleware-Layer.) +- **Rate-Limiting/Brute-Force** an Login, Reset, MFA, API — ergänzt den vorhandenen Konto-Lockout (IP- **und** kontobezogen). +- **Session-Härtung**: kurze Idle-/Absolute-Timeouts, **Session-Invalidierung** bei Passwort-Reset/Deaktivierung/MFA-Änderung, **„aktive Sitzungen" anzeigen + einzeln abmelden**. +- **Sichere Token-/Secret-Behandlung**: alle Tokens single-use + gehasht; Secrets nur aus Env/Secret-Store, nie im Repo; **Secret-Scanning** in CI. +- **Audit-/Security-Event-Log erweitern**: Logins (Erfolg/Fehlschlag), Rechteänderungen, MFA-Änderungen, Exporte, Admin-Aktionen; **append-only**/manipulationssicher; Aufbewahrung definiert. +- **Passwort-Breach-Check** beim Setzen (HaveIBeenPwned k-Anonymity) zusätzlich zur Policy. + +**P1 — kurz danach (Betrieb/Compliance):** +- **Tenant-Isolationstests** automatisiert (RLS-Regression) — Kernrisiko bei Multi-Tenant. +- **Verschlüsselung at rest** (DB + **Backups**), **TLS/HSTS** überall, Key-Rotation; TOTP-/sensible Felder verschlüsselt. +- **Backups + regelmäßige Restore-Tests** (dogfooding: das fordert ihr selbst als Control ein), DR-Konzept, RTO/RPO. +- **Dependency-/Container-Scanning** (SCA), **SAST**, `npm audit`/Renovate; Patch-SLA. +- **DSGVO-Funktionen** (Admin Phase 2): mandantenvollständiger **Export**, **Löschkonzept/Retention**, AVV/DPA-Bausteine, TOMs dokumentiert. +- **Impersonation** (Admin Phase 2) **nur** zeitlich begrenzt, protokolliert, mit „Support-Sitzung aktiv"-Banner (Support-Zugriff sicher machen). +- **E-Mail-Change-Verifizierung** (Double-Opt-in bei Adressänderung) + Benachrichtigung an alte Adresse. + +**P2 — mittelfristig / Reifegrad:** +- **WebAuthn/Passkeys**, **SSO (OIDC/SAML)** für Enterprise-Kunden (steht im Backlog). +- **Datei-Upload-Sicherheit** (sobald Storage kommt): AV-Scan, MIME/Größen-Limits, kein HTML-Serving, signierte URLs. +- **WAF/Reverse-Proxy** + DDoS-Schutz vor der App; least-privilege DB-User; Netzsegmentierung. +- **Responsible-Disclosure**: `security.txt`, Kontaktpfad, ggf. Bug-Bounty. +- **Externer Pen-Test** vor „Go-Live/Skalierung"; Ergebnisse als Maßnahmen ins eigene ISMS. +- **Incident-Response-Prozess** für Certvia selbst (passt zum NIS2-/Vorfälle-Modul, das ihr ohnehin baut). + +--- + +## 4. Vorschlag: Priorisierte Roadmap (integriert eure Punkte + P0) + +| Reihe | Paket | Inhalt | +|---|---|---| +| **1** | **Mail-Fundament** | Provider + SPF/DKIM/DMARC, Queue/Retry, Certvia-Templates, Benachrichtigungsregeln | +| **2** | **Auth-Self-Service** | Passwort-Reset (Token), Passwort selbst ändern, E-Mail-Change-Verifizierung, Session-Invalidierung | +| **3** | **MFA scharf** | Enrollment-Gate erzwingen, Recovery-Codes-Flow, TOTP-Secret verschlüsselt, Step-up für sensible Aktionen | +| **4** | **Plattform-Admin-Verwaltung** | Weitere Superadmins anlegen/verwalten, Rollen, Vier-Augen, Plattform-Audit | +| **5** | **Härtung P0** | Security-Header, Rate-Limiting, Audit-Erweiterung, Breach-Check, Secret-Scanning | +| **6+** | **P1/P2** | RLS-Tests, at-rest-Verschlüsselung, Backups/Restore, DSGVO, Impersonation, WebAuthn/SSO, Pen-Test | + +Pakete 1–4 sind stark verzahnt (alles hängt am Mail-Fundament); 5 läuft quer und sollte **mit** 1–4 kommen, nicht danach. + +--- + +## 5. Offene Entscheidungen (bevor wir Tasks schneiden) +1. **Mail-Provider**: API-Dienst (Postmark/SendGrid/SES …) **oder** eigener SMTP? (beeinflusst Zustellbarkeit, DSGVO-Ort, Aufwand) +2. **2FA-Ausbau**: reicht TOTP scharfschalten, oder direkt **WebAuthn/Passkeys** mitnehmen? +3. **Plattform-Admin-Rollen**: nur „Voll-Admin", oder abgestufte Rollen (Support/Read-only)? +4. **DSGVO-Umfang** jetzt (Export/Löschung/Retention) oder in eigener Runde? +5. **Team-Setup**: 1, 2 oder 3 Entwickler parallel — dann schneide ich analog zum Wizard vertikale Lanes. + +--- + +## 6. Nächster Schritt +Auf dieser Basis schneide ich — wie beim Wizard — **Entwickler-Aufgabenpakete** (mit Branch-Konvention unter `dev`, Akzeptanzkriterien, DoD). Sag mir die Antworten zu §5 (v. a. Mail-Provider und Team-Größe), dann lege ich los. Reihenfolge-Empfehlung: **Mail-Fundament zuerst**, weil Reset/Einladung/Benachrichtigung daran hängen. diff --git a/docs/wizard-uebergabe/00_Entwicklerpakete/Contracts-Checkliste-Kickoff.md b/docs/wizard-uebergabe/00_Entwicklerpakete/Contracts-Checkliste-Kickoff.md new file mode 100644 index 0000000..a5de6ff --- /dev/null +++ b/docs/wizard-uebergabe/00_Entwicklerpakete/Contracts-Checkliste-Kickoff.md @@ -0,0 +1,168 @@ +# Contracts-Checkliste — Kickoff Dev A × Dev B (15 Min.) + +> Zweck: Die Naht zwischen **Paket Dev A** (Wizard-Shell/Scoping/AL) und **Paket Dev B** +> (Engines/Fragebogen/Richtlinien) **einmal gemeinsam bestätigen**, bevor beide parallel starten. +> Grundlage: der identische *Contracts-Anhang* §1–§6 in beiden Entwicklerpaketen. +> Vorgehen: Punkt für Punkt durchgehen, abhaken, offene Entscheidungen unten eintragen, beide signieren. +> Danach laufen A und B konfliktarm parallel — einzige echte Nahtstellen sind +> `prisma/schema.prisma`, `scripts/check-module-guards.ts` und die Step-Registry. + +**Basis-Branch:** `dev` · **Feature-Branches:** `dev/a*-…` (A) bzw. `dev/b*-…` (B) · **PR-Ziel:** `dev` +Kein Push durch die Agenten; häufig auf `dev` rebasen; kleine PRs je Story. + +--- + +## §1 Task-Objekt — **Owner: Dev B** (A konsumiert) + +Dev B besitzt das Modell + `createTask`-Action; Dev A / Wizard-Gates rufen sie auf. + +- [ ] `type`: `document_create | evidence_provide | technical | organizational | validation | policy_approval` +- [ ] Felder: `owner`, `dueDate`, `priority: 'hoch'|'mittel'|'niedrig'`, `status` +- [ ] `resources` (JSON): `{ tool, budget, personnel, time }` +- [ ] `origin` (Herkunft/Trigger) vorhanden +- [ ] `links` (polymorph): `{ control?, risk?, document?, asset? }` +- [ ] Bestehender `policy_approval`-Flow bleibt unverändert lauffähig (Regression grün) +- [ ] **Signatur der `createTask`-Action steht fix**, bevor A ihre Gates verdrahtet + → Signatur hier notieren: `_____________________________________________` + +## §2 Validierungsstatus — **Owner: Dev A** (B konsumiert) + +- [ ] `enum ObjectReviewStatus { offen, in_bearbeitung, zur_validierung, validiert, zurueckgewiesen }` +- [ ] Zusatzfelder: `reviewComment`, `reviewerId` +- [ ] Regel bestätigt: **„Nur `validiert` zählt als bestätigt."** +- [ ] RBAC-Recht `validate_objects` + Rolle `external_validator` (klonbar) angelegt +- [ ] Feld-Konvention (an welchen Objekten der Status hängt) für Wizard-Gates fix + +## §3 Flags in `variables.schema.json` — **Owner: Dev B** (Namen fix, A entwickelt dagegen) + +- [ ] Namen unverändert übernommen (keine Umbenennung ohne beidseitige Abstimmung): + `FLAG_INCLUDE_SHOULD, FLAG_HIGH_PROTECTION, FLAG_VERY_HIGH_PROTECTION, + FLAG_ELEVATED_PROTECTION, FLAG_PERSONAL_DATA, FLAG_PROTOTYPE_PROTECTION, + FLAG_CLOUD_USED, FLAG_AI_USED, FLAG_OT_USED, FLAG_DEV_INHOUSE, FLAG_MOBILE_WORK, + FLAG_MOBILE_DEVICES, FLAG_CRYPTO_PKI, FLAG_EXTERNAL_IT, FLAG_CUSTOMER_SYSTEMS, + FLAG_ISB_EXTERNAL, FLAG_ISB_INTERNAL` +- [ ] `FLAG_ELEVATED_PROTECTION` bleibt **abgeleitet** (`applyProtection`) — nie manuell setzen +- [ ] Nach Schema-Änderung: `python3 seed/isms-vorlagenpaket-v2/_verify.py` → **OK** + +## §4 Prüfziele — beidseitig fix + +- [ ] Werte: `informationssicherheit | prototypenschutz | datenschutz` +- [ ] Wirkung bestätigt: Kapitel `8.x` nur bei Prototyp, `9.x` nur bei Datenschutz + +## §5 Step-Registry — **Owner: Dev A** (B konsumiert) + +- [ ] Signatur fix: `registerStep({ key, title, order, guard, component })` +- [ ] Schritt-Keys/Reihenfolge: + `1 scoping · 2 context · 3 roles · 4 policies · 5 assets · 6 risks · 7 controls · 8 gap · 9 readiness` +- [ ] Klar: **B liefert die Komponenten für `context` (Schritt 2) und `policies` (Schritt 4)**; + A stellt die Registry-Schnittstelle stabil bereit, bevor B einklinkt + +## §6 Migrations-Protokoll — beidseitig verbindlich + +- [ ] Vor jedem Migrations-Erzeugen zuerst auf `dev` rebasen +- [ ] **Migrationen nie gleichzeitig ohne Absprache** erstellen +- [ ] Je Branch **genau eine Migration pro Story** +- [ ] Prisma-7-Flow: `migrate diff --from-config-datasource … --to-schema … --script` + → RLS-DO-Block manuell anhängen → `migrate deploy` → `generate` +- [ ] Neue tenant-gebundene Modelle → `TENANT_MODELS` (`src/server/db.ts`) **und** RLS-Policy +- [ ] Neue Server-Action-Datei → in `scripts/check-module-guards.ts` eintragen (sonst Build-Fail) + +--- + +## Erwartete Migrations-Reihenfolge (gemeinsam festlegen) + +Beide erzeugen Migrationen an `schema.prisma` — Reihenfolge vorab abstimmen, um Konflikte zu vermeiden. +Vorschlag (an tatsächlicher Story-Reihenfolge ausrichten): + +| # | Story | Owner | Migration (Arbeitsname) | +|---|-------|-------|-------------------------| +| 1 | A1-1 | A | `onboarding_progress` | +| 2 | F1 | B | `tasks_wizard_fields` | +| 3 | F2 | A | (Enum `ObjectReviewStatus` + `external_validator`) | +| 4 | A2-2 | A | `wizard_scope` | +| 5 | B3 | B | `wizard_facts` | + +- [x] Reihenfolge oben bestätigt / angepasst — A1-1(A) → F1(B) → F2(A) → A2-2(A) → B3(B) +- [x] Wer erzeugt die **erste** Migration? → **Dev A** (`onboarding_progress`, A1-1) — von Dev B bestätigt; B rebast danach zuerst + +## Offene Fachpunkte (aus C0 — vor bzw. begleitend zu klären) + +- [ ] Neue `FLAG_*` in `variables.schema.json` ergänzt (F4, Dev B) +- [ ] Vorlagen `P01`/`D01` + `VA-20` angelegt (B4-3, Dev B) +- [ ] Baseline `BL-*` normalisiert +- [ ] ISB-Freigabe der neuen/geänderten Texte (fachlich, kein Code) + +--- + +## Sign-off + +- Dev A bestätigt §1–§6 + Migrations-Reihenfolge: **Claude (Dev A)** (Datum: 2026-07-28) +- Dev B bestätigt §1–§6 + Migrations-Reihenfolge: **Claude (Dev B)** (Datum: 2026-07-28) + +> Änderungen an §1–§6 nach dem Kickoff nur **gemeinsam** und mit Update dieser Datei +> **und** von `docs/STAND-dev-branch.md`. + +--- + +## Dev A — Kickoff-Vorbereitung (Positionen & Vorschläge, warten auf B-Bestätigung) + +> Nicht-bindend bis zum gemeinsamen Sign-off. „A-Vorschlag" = braucht B's Ja; „A bestätigt" = +> liegt in A's Hoheit und ist von A's Seite geklärt. + +**§1 Task-Objekt (Owner B):** A bestätigt die Feldliteralwerte (`type`-Werte, `priority`, `resources`, +`origin`, `links`) wie im Anhang. **A braucht von B eine fixe `createTask`-Signatur, bevor A Gates/Trigger +verdrahtet.** A-Vorschlag als Startpunkt: +`createTask(input: { type, title, origin, owner?, dueDate?, priority?, resources?, links? }): Promise<Task>` +(Server-Action in B's Hoheit; A ruft nur auf). → **B bestätigt/ändert Signatur:** ✅ **bestätigt (unverändert)** — +`createTask(input: { type, title, origin, owner?, dueDate?, priority?, resources?, links? }): Promise<Task>`. +Mapping/Defaults (B-Hoheit, F1): `owner` → DB-Spalte `assigneeId` (eine verantwortliche Person; optional, da B1-Vorschläge unassigned starten); +`priority` default `'mittel'`; `resources = { tool?, budget?, personnel?, time? }` (alle optional); `links = { control?, risk?, document?, asset? }` (IDs/Refs). +`status` setzt die Action **serverseitig** (Default `OPEN`; auto-generierte B1-Vorschläge starten im Vorschlags-Status zur Bestätigung) — **kein** Input-Feld. +Bestehende `entityType/entityId/entityRef` bleiben für den `policy_approval`-Flow erhalten (F1 fügt nur Felder hinzu); `links.document` bildet den Dokumentbezug ab. + +**§2 Validierungsstatus (Owner A) — A bestätigt:** +- `enum ObjectReviewStatus { offen, in_bearbeitung, zur_validierung, validiert, zurueckgewiesen }` + `reviewComment`, `reviewerId`. +- Regel „Nur `validiert` zählt als bestätigt" gilt für alle Wizard-Gates. +- RBAC-Recht `validate_objects` + klonbare Rolle `external_validator`. +- **Feld-Konvention (Gate-Quelle):** In A1-1 trägt der Schritt-Datensatz `OnboardingProgress` den Review-Status; + das „Weiter"-Gate liest den Status des Vorgänger-Schritts. Sobald Domänenobjekte je Schritt existieren + (spätere Stories), wandert die Statusquelle auf das jeweilige Primärobjekt (Generalisierung = A3). + → **B nimmt das für seine Schritte (2 context, 4 policies) so an:** ✅ **ja** — B liest für `context` (2) und `policies` (4) + den Review-Status des Vorgänger-Schritts aus `OnboardingProgress` (Quelle A1-1); „nur `validiert` zählt". B schreibt in diesen Schritten + nur Fakten/Flags bzw. Richtlinien-Objekte, **nicht** den Gate-Status selbst. Hinweis: Schritt 4 nutzt weiterhin den bestehenden + `policy_approval`-Workflow für die inhaltliche Freigabe; das Wizard-„Weiter"-Gate hängt aber am `OnboardingProgress`-Status, nicht am Task. + +**§3 Flags (Owner B):** A übernimmt die Namen aus §3 **unverändert**, benennt nichts um, behandelt +`FLAG_ELEVATED_PROTECTION` als abgeleitet (nie manuell). A entwickelt `scope-filter.ts` gegen diese Namen, +**bevor** F4 landet. → **B bestätigt Namensliste final:** ✅ **final** — die 17 Namen bleiben unverändert. Ist-Stand geprüft: +**14 bereits** in `variables.schema.json` vorhanden; F4 ergänzt **genau die 3 fehlenden** `FLAG_PROTOTYPE_PROTECTION`, `FLAG_ISB_EXTERNAL`, +`FLAG_ISB_INTERNAL` (+ fehlende `ROLE_*/TECH_*` aus C2, **ohne** FLAG-Namen anzufassen). `FLAG_ELEVATED_PROTECTION` bleibt abgeleitet. Nach F4: `_verify.py` → OK. + +**§4 Prüfziele:** A bestätigt `informationssicherheit | prototypenschutz | datenschutz`; Kap. `8.x` nur bei +Prototyp, `9.x` nur bei Datenschutz (C1-Methodik). + +**§5 Step-Registry (Owner A) — A bestätigt & stellt bereit:** +- Signatur `registerStep({ key, title, order, guard, component })`, Keys/Reihenfolge + `1 scoping · 2 context · 3 roles · 4 policies · 5 assets · 6 risks · 7 controls · 8 gap · 9 readiness`. +- A liefert die stabile Registry-Schnittstelle in A1-1, **bevor** B `context` (2) und `policies` (4) einklinkt. + → **B bestätigt Schnittstelle als ausreichend:** ✅ **ausreichend** — `registerStep({ key, title, order, guard, component })` + Keys 1–9 + genügen, um `context` (2) und `policies` (4) einzuklinken. Einzige Bitte an A: `guard` muss das **Ausblenden** eines Schrittes erlauben + (z. B. `policies` nur bei aktivem Richtlinien-Modul) und die `component`-Client/Server-Boundary sauber halten. Keine weiteren Felder von B benötigt. + +**§6 Migrations-Reihenfolge — A-Vorschlag:** + +| # | Story | Owner | Migration | Anmerkung | +|---|-------|-------|-----------|-----------| +| 1 | A1-1 | A | `onboarding_progress` | **A erzeugt die erste Migration** | +| 2 | F1 | B | `tasks_wizard_fields` | B rebast danach zuerst auf `dev` | +| 3 | F2 | A | `object_review_status` (Enum + `external_validator`) | | +| 4 | A2-2 | A | `wizard_scope` | | +| 5 | B3 | B | `wizard_facts` | | + +→ **Wer erzeugt die erste Migration? A-Vorschlag: Dev A (A1-1).** B bestätigt: ✅ **ja** — Dev A erzeugt `onboarding_progress` zuerst; +B rebast danach zuerst auf `dev` und erzeugt dann `tasks_wizard_fields` (F1). +→ Reihenfolge oben bestätigt/angepasst: ✅ **bestätigt (unverändert)** — A1-1(A) → F1(B) → F2(A) → A2-2(A) → B3(B); je Branch genau eine Migration, nie gleichzeitig. + +**Nicht-blockierend für A1-1** (betrifft spätere A-Stories bzw. B/Berater): neue `FLAG_*` in +`variables.schema.json` (F4), `seed/scoping/c1-scope.json` erzeugt A aus der C1-Tabelle (445 Zeilen), +P01/D01/VA-20 + Baseline-Normalisierung (B4/Berater), ISB-Freigabe (fachlich). diff --git a/docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevA-Wizard-Scoping.md b/docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevA-Wizard-Scoping.md new file mode 100644 index 0000000..d3abf9f --- /dev/null +++ b/docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevA-Wizard-Scoping.md @@ -0,0 +1,82 @@ +# Umsetzungspaket **Dev A** — Wizard-Fundament, Scoping & AL2/AL3 zentral + +> Claude-Code-Prompt für Entwickler A. Parallel zu **Paket Dev B**. Basis-Branch **`dev`**. Fachcontent: `Fachcontent_Wizard_C1-C9/C1_Scoping-AL-Pruefziel.md`. Repo-Doku: `docs/HANDOVER-DEV.md`, `STAND-dev-branch.md`. + +## Auftrag (Kurz) +Baue das **Wizard-Grundgerüst**, den **Scoping-Schritt** und verlege den **AL2/AL3-Schalter zentral ins Admin-/Superadmin-Portal**. Du lieferst die Klammer, in die Dev B seine Schritt-Inhalte einklinkt. + +## Branches (unter `dev` abzweigen, PR-Ziel `dev`) +- `dev/a1-wizard-shell` +- `dev/a2-scoping-admin-al` +Häufig auf `dev` rebasen. Kleine PRs je Story. + +## Datei-Hoheit (nur DU fasst diese an) +`src/app/(app)/onboarding/**` · `src/server/actions/onboarding.ts` · `src/lib/scope-filter.ts` · `src/app/(platform)/admin/**` (AL-Einstellung) · `src/lib/modules.ts` (nur Eintrag `onboarding`) · Scope-/Progress-Modelle in `prisma/schema.prisma`. +**Koordiniert (mit Dev B abstimmen, siehe Contracts-Anhang):** `prisma/schema.prisma` (Migrations-Reihenfolge), `scripts/check-module-guards.ts` (deine neuen Actions eintragen), Validierungsstatus-Enum. + +--- + +## Story A1 — Wizard-Shell & Navigation (`dev/a1-wizard-shell`) + +**A1-1 Step-Registry & State-Machine (L)** +- Neues Modul **`onboarding`** in `src/lib/modules.ts` (Default aktiv für Bestands-Tenants). +- Bereich `src/app/(app)/onboarding/**` mit einer **Step-Registry**: Schritte registrieren sich mit `{ key, title, order, guard, component }`. Dev B klinkt „context" (Schritt 2) und „richtlinien" (Schritt 4) ein — definiere die Registry-Schnittstelle stabil (Contracts-Anhang §5). +- **State-Machine**: `offen → in_bearbeitung → zur_validierung → validiert` je Schritt; **Gate**: „Weiter" ist gesperrt, solange das Vorgänger-Objekt nicht `validiert` ist (nutzt Validierungsstatus, Contracts §2). +- **Persistenter Fortschritt** je Mandant: Modell `OnboardingProgress` (tenant-gebunden, `TENANT_MODELS`+RLS), Migration `onboarding_progress`. +- Server-Action-Datei `src/server/actions/onboarding.ts` über `moduleGuard("onboarding")`; in `scripts/check-module-guards.ts` eintragen. +- **AK:** Fortschritt resumierbar; Gate blockiert korrekt; Schritte via Registry einklinkbar; `build`/Guard-Check grün. + +**A1-2 Dashboard-Kachel (S)** +- Kachel „Onboarding-Fortschritt" in `dashboard/page.tsx` analog der bestehenden Freigabe-Kachel (Anteil erledigter Schritte, nächster offener Schritt). + +--- + +## Story F2 (dein Anteil der Foundation) — Validierungsstatus-Enum (`dev/a1-wizard-shell`) +- Lege das **wiederverwendbare Enum** `ObjectReviewStatus` + Feld-Konvention an (Contracts §2), das Wizard-Gates und später A3 nutzen. RBAC-Recht `validate_objects`; Rolle **`external_validator`** ergänzen. +- **AK:** Enum + Recht vorhanden; Wizard-Gate liest den Status; Rolle im RBAC klonbar. +- **Hinweis:** Die vollständige Generalisierung über alle Objekttypen ist Story A3 (späterer Branch) — hier nur Enum + Wizard-Nutzung. + +--- + +## Story A2 — Scoping + AL2/AL3 zentral im Adminportal (`dev/a2-scoping-admin-al`) + +**A2-1 AL2/AL3 zentral (M)** — *explizite Anforderung* +- Der Assessment-Level (AL2/AL3) wird **ausschließlich** im **Admin-/Superadmin-Portal je Mandant** gesetzt → **einzige Quelle der Wahrheit**. UI in `src/app/(platform)/admin/**`, Action in `src/server/actions/admin.ts`/`platform.ts`. +- Mandanten-`/settings` und der Scoping-Schritt zeigen AL nur **read-only** an (kein Änderungsrecht mehr im Tenant). +- AL treibt die bestehenden Flags `FLAG_HIGH_PROTECTION`/`FLAG_VERY_HIGH_PROTECTION` und den vorhandenen Coverage-Filter (Coverage zeigt bei AL2 keine „sehr hoch"-Controls — Verhalten beibehalten, Quelle umziehen). +- **AK:** AL ist nur im Adminportal änderbar; Änderung propagiert in Coverage + Zusatzanforderungen; Tenant kann AL nicht mehr selbst setzen. + +**A2-2 Scope-Objekt + Filter-Engine (M)** +- Scoping (Schritt 1) erfasst: **Prüfziele** (Informationssicherheit / Prototypenschutz / Datenschutz), Standorte, Geltungsbereich, Ausschlüsse → Modell `WizardScope` (tenant-gebunden, RLS). +- **`src/lib/scope-filter.ts`**: gegeben (AL, gesetzte `FLAG_*`, aktive Prüfziele) → liefert die **aktiven Anforderungen**. Datengrundlage: **C1-Tabelle** (412 Zeilen: `Control · Anforderungs-ID · Typ · AL2 · AL3 · Prüfziel · Scope-Bedingung(Flag)`), als Seed/JSON `seed/scoping/c1-scope.json` einlesen (ID = `mapping.json`-`id`). +- Filterlogik exakt nach C1-Methodik: MUSS/SOLL = AL2+AL3 (SOLL über `FLAG_INCLUDE_SHOULD`); HOCH nur bei `FLAG_HIGH_PROTECTION`; SEHR HOCH nur bei `FLAG_VERY_HIGH_PROTECTION`; Kapitel 8.x nur bei Prüfziel Prototyp, 9.x nur bei Datenschutz. +- **AK / Tests:** Unit-Tests gegen repräsentative C1-Zeilen (z. B. `1.2.2-H1` erscheint nur bei `FLAG_HIGH_PROTECTION`; `1.1.1-S1` nur bei `FLAG_INCLUDE_SHOULD`; `8.*` nur bei Prototyp). Geänderter Scope blendet nachgelagerte Schritte korrekt. + +**Fachcontent:** `C1_Scoping-AL-Pruefziel.md`. **Abhängigkeit:** A1 (Shell), Contracts §2 (Status), §3 (Flags-Namen von Dev B/F4 — bis dahin gegen die im Contracts-Anhang fixierten Namen entwickeln). + +--- + +## Definition of Done (jede Story) +`npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check) grün · neue Action in `check-module-guards.ts` · neue tenant-Modelle in `TENANT_MODELS`+RLS+Migration (RLS-DO-Block) · Browser-Verifikation · Demo-Seed lauffähig. + +## Reihenfolge +A1-1 → F2 → A1-2 → A2-1 → A2-2. Danach (Folge-Paket): A3 (Validierung generalisieren), A5/A6/A7/A8. + +--- + +## Contracts-Anhang (identisch in Paket A und B — an der Naht abstimmen) + +**§1 Task-Objekt (Dev B besitzt das Modell, du konsumierst es):** +`Task { type: 'document_create'|'evidence_provide'|'technical'|'organizational'|'validation'|'policy_approval', owner, dueDate, priority: 'hoch'|'mittel'|'niedrig', status, resources: {tool,budget,personnel,time}, origin, links: {control?,risk?,document?,asset?} }`. Gates/Trigger erzeugen Aufgaben über die Action von Dev B. + +**§2 Validierungsstatus (du besitzt das Enum):** +`enum ObjectReviewStatus { offen, in_bearbeitung, zur_validierung, validiert, zurueckgewiesen }` + `reviewComment`, `reviewerId`. Rolle `external_validator`. „Nur `validiert` zählt als bestätigt." + +**§3 Flags (Dev B pflegt `variables.schema.json`, Namen sind fix):** +`FLAG_INCLUDE_SHOULD, FLAG_HIGH_PROTECTION, FLAG_VERY_HIGH_PROTECTION, FLAG_ELEVATED_PROTECTION, FLAG_PERSONAL_DATA, FLAG_PROTOTYPE_PROTECTION, FLAG_CLOUD_USED, FLAG_AI_USED, FLAG_OT_USED, FLAG_DEV_INHOUSE, FLAG_MOBILE_WORK, FLAG_MOBILE_DEVICES, FLAG_CRYPTO_PKI, FLAG_EXTERNAL_IT, FLAG_CUSTOMER_SYSTEMS, FLAG_ISB_EXTERNAL, FLAG_ISB_INTERNAL`. + +**§4 Prüfziele:** `informationssicherheit | prototypenschutz | datenschutz`. + +**§5 Step-Registry (du definierst, B konsumiert):** `registerStep({ key, title, order, guard, component })`; Schritt-Keys: `1 scoping · 2 context · 3 roles · 4 policies · 5 assets · 6 risks · 7 controls · 8 gap · 9 readiness`. + +**§6 Migrations-Protokoll:** Vor dem Erzeugen einer Migration auf `dev` rebasen; Migrationen nie gleichzeitig ohne Absprache erstellen; je Branch genau eine Migration pro Story. diff --git a/docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevB-Engines-Richtlinien.md b/docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevB-Engines-Richtlinien.md new file mode 100644 index 0000000..f955a2a --- /dev/null +++ b/docs/wizard-uebergabe/00_Entwicklerpakete/Paket-DevB-Engines-Richtlinien.md @@ -0,0 +1,100 @@ +# Umsetzungspaket **Dev B** — Aufgaben, Regel-Engine, Fragebogen & Richtlinien-Import/Upload + +> Claude-Code-Prompt für Entwickler B. Parallel zu **Paket Dev A**. Basis-Branch **`dev`**. Fachcontent: `C2_Fragenkatalog-Wirkung.md`, `C3_Vorlagen-Annotation.md`, `C0_README` (offene Punkte). Repo-Doku: `docs/HANDOVER-DEV.md`, `STAND-dev-branch.md`. + +## Auftrag (Kurz) +Baue die **Regel-Engine**, den **Fragebogen**, die **Aufgaben-Erzeugung** und die **Richtlinien: Import bei Modul-Aktivierung + manueller Upload**. Du lieferst die Inhalte/Engines, die sich in die Wizard-Shell von Dev A einklinken. + +## Branches (unter `dev` abzweigen, PR-Ziel `dev`) +- `dev/b1-tasks-erweiterung` +- `dev/b2-regel-engine` +- `dev/b3-fragebogen` +- `dev/b4-richtlinien-import-upload` +Häufig auf `dev` rebasen. Kleine PRs je Story. + +## Datei-Hoheit (nur DU fasst diese an) +`src/server/actions/tasks.ts` (Task-Modell/Logik) · `src/lib/rules/**` · `seed/isms-vorlagenpaket-v2/variables.schema.json` · Fragebogen unter `src/app/(app)/onboarding/steps/context/**` und `.../policies/**` (in Dev-A-Registry eingeklinkt) · `prisma/import-policies.ts` · `src/app/(app)/policies/**` (Upload/Import-Einstieg) · `seed/isms-vorlagenpaket-v2/` (P01/D01/VA-20). +**Koordiniert (mit Dev A abstimmen):** `prisma/schema.prisma` (Migrations-Reihenfolge), `scripts/check-module-guards.ts`, Step-Registry-Schnittstelle (§5). + +--- + +## Story F1 — Aufgaben-Objekt-Schema erweitern (`dev/b1-tasks-erweiterung`) +- Erweitere das bestehende `Task`/`TaskComment` (heute Typ `policy_approval`) um die Felder aus Contracts §1 (`type`, `owner`, `dueDate`, `priority`, `status`, `resources` JSON, `origin`, polymorphe `links`). Bestehender Freigabe-Flow bleibt lauffähig. +- Migration `tasks_wizard_fields`; `TENANT_MODELS`+RLS bleiben. +- **AK:** neue Felder vorhanden/typisiert; `policy_approval`-Flow unverändert grün. + +## Story B1 — Auto-Generierung mit Bestätigung (`dev/b1-tasks-erweiterung`) +- Aus Triggern (Schritt 3/4/6/7/8 + Zurückweisung) **Aufgabenvorschlag** erzeugen (Vorschlag → Bearbeiter bestätigt/verwirft). Trigger-Set exakt aus **C2 §8** (z. B. „ISB nicht benannt" → `organizational`/Control 1.2.2; „externe IT-Dienstleister = ja" → `evidence_provide`/Control 6.1.1; „kein Restore-Test" → `technical`/BL-OPS-06/Control 5.2.9). +- Anzeige/Filter im Modul „Aufgaben" (`src/app/(app)/tasks/`), Ressourcenfelder editierbar. +- **AK:** Trigger erzeugt korrekt verknüpften Vorschlag; Bestätigung übernimmt; Verwerfen dokumentiert. + +--- + +## Story F4 — Variablen/Flags erweitern (`dev/b2-regel-engine`) +- In `seed/isms-vorlagenpaket-v2/variables.schema.json` ergänzen: `FLAG_PROTOTYPE_PROTECTION`, `FLAG_ISB_EXTERNAL`, `FLAG_ISB_INTERNAL` + fehlende `ROLE_*`/`TECH_*` aus C2. Namen = Contracts §3 (fix, da Dev A darauf entwickelt). +- **AK:** `python3 seed/isms-vorlagenpaket-v2/_verify.py` → **OK**. + +## Story F3 + B2 — Regel-/Mapping-Engine (`dev/b2-regel-engine`) +- **DSL** (Contracts §7) als Typen in `src/lib/rules/dsl.ts`; **Engine** in `src/lib/rules/engine.ts`: `Bedingung(Antwort|Scope|Flag) → Wirkung(Klausel ein/aus · Control relevant · Risiko/Asset-Bezug · Aufgabe)`. +- Koppelt an vorhandene `{{#if FLAG}}`-Render-Flags und die Lieferanten-Anforderungs-Engine (Muster). +- **Regeldaten** aus **C2 §5** (Q-FEAT-01…10) als Regelobjekte hinterlegen (z. B. `FLAG_CLOUD_USED` → R12-Klauseln + Controls 5.3.2/5.3.4/6.1.3 + Risiken R-CLOUD-*). +- **AK / Tests:** Unit-Tests, die für jede Q-FEAT-Antwort die erwarteten Wirkungen prüfen; Antwortänderung propagiert deterministisch. + +## Story B3 — Fragebogen/Fakten (Schritt 2) (`dev/b3-fragebogen`) +- Dynamischer, **bedingter** Fragebogen mit Abschnitten **A–F aus C2** (Antworttypen + Anzeige-Bedingungen); Antworten als **wiederverwendbare Faktenobjekte** (Migration `wizard_facts`, RLS). +- Abschnitt **E** (Baseline) als **vorbelegte Defaults** aus `Technische-Sicherheits-Baseline.md` — nur bestätigen/anpassen, keine Ersteingabe. +- Zentrale Variablen bleiben serverseitig gesperrt (nur `/settings`, siehe `src/lib/policy-variables.ts`) — Fragebogen schreibt Fakten/Flags, nicht die gesperrten Variablen. +- Einklinken über Dev-A-Step-Registry (§5), Schritt-Key `context`. +- **AK:** Fragen A–F vorhanden; bedingte Sichtbarkeit über Flags; Antwort propagiert in abhängige Objekte (via B2); Baseline-Defaults vorbelegt. + +--- + +## Story B4 — Richtlinien: Import bei Aktivierung + manueller Upload (`dev/b4-richtlinien-import-upload`) + +**B4-1 Vorlagen-Import bei Modul-Aktivierung (M)** — *explizite Anforderung* +- Aktiviert der Superadmin das **Richtlinien-Modul** für einen Mandanten, wird das Vorlagenpaket **mandantenweit nicht-destruktiv importiert**: kapsle die bestehende Logik `prisma/import-policies.ts` (Diff/Upsert/`archivedAt`, `{dryRun}`) als **serverseitig aufrufbare Action/Job**. Zusätzlich Button „Vorlagen importieren/aktualisieren" in Admin **und** unter `/policies`. +- **AK:** Modul-Aktivierung triggert Import; idempotent; Status/Freigabe/Overrides/Variablenwerte bleiben erhalten; Änderungsreport sichtbar. + +**B4-2 Manueller Upload eigener Richtlinien im Menü (M)** — *explizite Anforderung; Storage später* +- Unter `/policies` Einstieg „Eigene Richtlinie hochladen" mit **Pflicht-Control-Zuordnung** (Multi-Select aus Control-Katalog, optional Anforderungs-IDs) gemäß **C3 §4**. +- Datei-Persistenz über ein **gestubbtes Storage-Adapter-Interface** `src/server/storage/adapter.ts` (echtes Backend = Folge-Epic S1). Upload legt Metadaten + Block-Modell + Control-Mapping an; die Zuordnung fließt wie ein `<!-- REQ -->`-Anker in die Nachweislage (Schritt 7). +- **AK:** „Eigene Richtlinie hochladen" vorhanden mit Control-Zuordnung; Storage-Adapter gekapselt (später ohne UI-Änderung verdrahtbar); hochgeladenes Dokument erscheint in der Coverage/Nachweislage. + +**B4-3 Proto/DS-Vorlagen P01/D01 + VA-20 + mapping.json (M)** +- Neue Vorlagen `P01_Prototypenschutz.md` (+ Verfahren `VA-20_Prototypen-Zutritt-und-Transport`) und `D01_Datenschutz.md` nach **C3 §2-Konvention** anlegen; `mapping.json`-Einträge im gleichen Schema für 8.x/9.x (IDs aus C1/C6-Dekomposition); Prototyp-Klauseln in `{{#if FLAG_PROTOTYPE_PROTECTION}}`. +- `_verify.py` um die neuen Verzeichnisse/Anker erweitern. +- **AK:** `python3 _verify.py` → **OK**; neue Anforderungen erscheinen im Scope, wenn Prüfziel Prototyp/Datenschutz aktiv (Dev-A-Filter). + +**Fachcontent:** `C3` (Annotationskonvention + P01/D01), `C2` (Flag-Wirkung), `C0` (offene Punkte 1–3). + +--- + +## Definition of Done (jede Story) +`npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check) grün · neue Action in `check-module-guards.ts` · neue tenant-Modelle in `TENANT_MODELS`+RLS+Migration (RLS-DO-Block) · bei Seed-Änderung `_verify.py` → **OK** · Browser-Verifikation. + +## Reihenfolge +F1 → B1 → F4 → (F3+B2) → B3 → B4-1 → B4-2 → B4-3. Danach (Folge-Paket): A6-Risikokatalog-Anbindung (C4), B5 Umsetzungshinweise (C6), B6 Versionierung, B7 Export (C9). + +--- + +## Contracts-Anhang (identisch in Paket A und B — an der Naht abstimmen) + +**§1 Task-Objekt (du besitzt das Modell):** +`Task { type: 'document_create'|'evidence_provide'|'technical'|'organizational'|'validation'|'policy_approval', owner, dueDate, priority: 'hoch'|'mittel'|'niedrig', status, resources: {tool,budget,personnel,time}, origin, links: {control?,risk?,document?,asset?} }`. Dev A/Wizard-Gates rufen deine `createTask`-Action zum Erzeugen von Aufgaben. + +**§2 Validierungsstatus (Dev A besitzt das Enum, du konsumierst):** +`enum ObjectReviewStatus { offen, in_bearbeitung, zur_validierung, validiert, zurueckgewiesen }` + `reviewComment`, `reviewerId`. Rolle `external_validator`. + +**§3 Flags (du pflegst `variables.schema.json`, Namen sind fix):** +`FLAG_INCLUDE_SHOULD, FLAG_HIGH_PROTECTION, FLAG_VERY_HIGH_PROTECTION, FLAG_ELEVATED_PROTECTION, FLAG_PERSONAL_DATA, FLAG_PROTOTYPE_PROTECTION, FLAG_CLOUD_USED, FLAG_AI_USED, FLAG_OT_USED, FLAG_DEV_INHOUSE, FLAG_MOBILE_WORK, FLAG_MOBILE_DEVICES, FLAG_CRYPTO_PKI, FLAG_EXTERNAL_IT, FLAG_CUSTOMER_SYSTEMS, FLAG_ISB_EXTERNAL, FLAG_ISB_INTERNAL`. + +**§4 Prüfziele:** `informationssicherheit | prototypenschutz | datenschutz`. + +**§5 Step-Registry (Dev A definiert, du konsumierst):** `registerStep({ key, title, order, guard, component })`; du lieferst Komponenten für `context` (Schritt 2) und `policies` (Schritt 4). + +**§6 Migrations-Protokoll:** Vor dem Erzeugen einer Migration auf `dev` rebasen; Migrationen nie gleichzeitig ohne Absprache erstellen; je Branch genau eine Migration pro Story. + +--- + +## Gemeinsamer Kickoff (15 Min., beide Entwickler, vor Story-Start) +Contracts §1–§6 gemeinsam bestätigen (Feldnamen, Enum-Werte, Flag-Namen, Registry-Signatur, Migrations-Reihenfolge). Danach arbeiten beide Pakete konfliktarm parallel; einzige echte Nahtstellen sind `schema.prisma`, `check-module-guards.ts` und die Step-Registry — alle drei sind im Contracts-Anhang fixiert. diff --git a/docs/wizard-uebergabe/01_Planung/Berater-Anweisung-Fachcontent.md b/docs/wizard-uebergabe/01_Planung/Berater-Anweisung-Fachcontent.md new file mode 100644 index 0000000..fa588be --- /dev/null +++ b/docs/wizard-uebergabe/01_Planung/Berater-Anweisung-Fachcontent.md @@ -0,0 +1,68 @@ +# Anweisung an den Berater — Fachcontent-Zulieferung (parallel zur Entwicklung) + +Der Onboarding-Wizard hat seinen größten Engpass **nicht im Code, sondern im Fachcontent**. Die folgenden Arbeitspakete **C1–C9** laufen **parallel** zur Entwicklung und schalten jeweils eine oder mehrere Entwickler-Epics scharf. Bitte im angegebenen **Format** liefern und die **„muss vorliegen bis"**-Reihenfolge einhalten — sonst werden C2/C3/C4/C5/C6 zum kritischen Pfad. + +> Bezug: Entwickler-Epics siehe `Wizard-Entwickler-Backlog.md`. Bestehendes Vorlagenpaket: `seed/isms-vorlagenpaket-v2/` (34 Dokumente, `mapping.json`, `_verify.py`). + +--- + +## Übersicht (was schaltet was frei) + +| WP | Inhalt | Schaltet frei | Format | Muss vorliegen bis | +|---|---|---|---|---| +| **C1** | AL2/AL3-Kennzeichnung + Prüfziel-Zuordnung je Control | A2 (Scoping/Filter) | Tabelle/CSV je Control | vor M2 | +| **C2** | Fragenkatalog + Antwort→Wirkung-Mapping | B2 Regel-Engine, B3 Fragebogen | strukturierte Tabelle | vor M1/M2 | +| **C3** | Regelfähige Vorlagen-Auszeichnung | B4 Richtlinien | Annotation im Vorlagenpaket | vor M2 | +| **C4** | VDA-/Standard-Risiko-Katalog + Standardmaßnahmen | A6 Risiko | Tabelle/CSV | vor M4 | +| **C5** | Reifegrad-Logik je Control | A7 Control-Assessment | Regeltabelle | vor M5 | +| **C6** | Umsetzungshinweise je Teilanforderung | B5 + A7 | strukturierter Text je Anforderung | fortlaufend, Kern vor M3 | +| **C7** | ISMS-Soll-Rollenmodell + Funktionstrennung | A4 Rollen | Regelliste + Vorlagen | vor M3 | +| **C8** | Priorisierungslogik Gap + Quick-Wins | A8 Gap | Regeltext | vor M6 | +| **C9** | Auswertungs-/Interpretationstexte + Export-Layout | B7 Readiness | Text + Layout-Skizze | vor M6 | + +--- + +## Arbeitspakete im Detail + +### C1 — Scoping-Grundlage (→ A2) +Je VDA-ISA-Control angeben: Zutreffen bei **AL2 / AL3** (SEHR HOCH), Zuordnung zu **Prüfzielen** (Info-Sicherheit / Prototypenschutz / Datenschutz), typische **Ausschluss-/Scope-Regeln**. +**Format:** eine Zeile je Control/Teilanforderung mit Spalten `Control-ID · Typ (MUSS/SOLL/HOCH/SEHR HOCH) · AL2? · AL3? · Prüfziel · Scope-Bedingung`. (Baut auf den vorhandenen Flags/Typen im `mapping.json` auf.) + +### C2 — Fragenkatalog + Antwort→Wirkung-Mapping (→ B2, B3) +Der geführte Fragebogen (Schritt 2) **und** die Regel-Engine hängen hieran. Je Frage: Text, Antworttyp, **Bedingung** (wann anzeigen), und die **Wirkung** jeder Antwort: welche **Variable/Platzhalter** gefüllt wird, welche **Klausel** ein-/ausgeblendet wird, welche **Controls/Assets/Risiken** betroffen sind, ob eine **Aufgabe** entsteht. +**Format:** Tabelle `Frage-ID · Frage · Antwortoptionen · Anzeige-Bedingung · Wirkung(Variable / Klausel / Control / Risiko / Aufgabe)`. **Kritischer Pfad — bitte zuerst.** + +### C3 — Regelfähige Vorlagen-Auszeichnung (→ B4) +Die 34 Vorlagen so **annotieren**, dass klar ist: welche **Klausel/Baustein** bei welcher **Antwort/Flag** erscheint bzw. entfällt, und welche **Controls** ein Dokument belegt. +**Format:** Auszeichnung direkt im Vorlagenpaket-Stil (bestehende `{{#if FLAG}}`-Mechanik + `mapping.json`-Control-Verknüpfung); danach `python3 _verify.py` → **OK**. + +### C4 — Risiko-Katalog (→ A6) +Kuratierter **Standard- und VDA-geforderter Risiko-Katalog**: je Risiko Beschreibung, betroffene **Assets/Controls**, empfohlene **Standardmaßnahmen**, Default-Bewertungshinweis. +**Format:** Tabelle `Risiko-ID · Titel · Beschreibung · Controls · Asset-Typen · Standardmaßnahme(n) · Default-Einschätzung`. + +### C5 — Reifegrad-Logik (→ A7) +Regeln, wie aus vorhandenen **Belegen** (Dokument/Risiko/Asset + Validierungsstatus) ein **Reifegrad-Vorschlag** je Control entsteht, und was der **Zielreifegrad** ist. Vorschlag ist regelbasiert, **Bestätigung durch Bearbeiter Pflicht**. +**Format:** Regeltabelle `Control · Bedingung(Belege) · Reifegrad-Vorschlag · Zielreifegrad · offene-Punkt-Kriterium`. + +### C6 — Umsetzungshinweise (→ B5, A7) +Je **Teilanforderung** ein Hinweis mit: **organisatorischer** Umsetzungsoption, **technischer** Option, typischen **Nachweisen**, passender **Vorlage** (Verweis), **Ressourcenindikation** (Tool/Personal/Budget/Zeit). Filterbar nach AL2/AL3. +**Format:** strukturierter Block je Anforderungs-ID (Felder org/tech/Nachweise/Vorlage/Ressourcen). **Fortlaufend, Kern-Set vor M3.** + +### C7 — ISMS-Soll-Rollenmodell + Funktionstrennung (→ A4) +Soll-Rollen (GF, ISB, DSB, IT-Verantwortung), **Funktionstrennungs-Regeln** (welche Kombination unzulässig), und die **Bestellungs-/Ernennungs-Vorlagen** (ISB-Bestellung etc.) mit Rollen-Platzhaltern. +**Format:** Regelliste + Vorlagen im Paket-Stil (Platzhalter). + +### C8 — Priorisierungslogik Gap (→ A8) +Wie offene Punkte priorisiert werden (Muss-/AL3-kritisch = hoch), Dedup-Kriterien, Definition **Quick-Wins**. +**Format:** kurzer Regeltext + Beispiel-Priorisierung. + +### C9 — Auswertung & Export (→ B7) +Interpretationstexte fürs Reifegrad-Dashboard, empfohlene nächste Schritte vor dem Assessment, und das **Layout des VDA-ISA-Katalog-Exports** (Reihenfolge, Felder, „bestätigt/unbestätigt"). +**Format:** Textbausteine + Layout-Skizze. + +--- + +## Prozess-Hinweise +- Zulieferung **iterativ** je Kapitel/Control-Gruppe möglich (nicht „alles auf einmal") — die Entwicklung kann teilbefüllt starten. +- **ISB-Freigabe** der neuen/angepassten Texte (VA/Richtlinien) ist ein eigener fachlicher Schritt (steht bereits offen auf `dev`). +- Alle Vorlagen-/Katalog-Änderungen nach dem Einspielen mit **`python3 seed/isms-vorlagenpaket-v2/_verify.py` → OK** gegenprüfen. diff --git a/docs/wizard-uebergabe/01_Planung/Onboarding-Wizard-Machbarkeitsanalyse.md b/docs/wizard-uebergabe/01_Planung/Onboarding-Wizard-Machbarkeitsanalyse.md new file mode 100644 index 0000000..eee4db7 --- /dev/null +++ b/docs/wizard-uebergabe/01_Planung/Onboarding-Wizard-Machbarkeitsanalyse.md @@ -0,0 +1,120 @@ +# Onboarding-Wizard — Machbarkeitsanalyse (Product Owner) + +Bewertung des Berater-Fahrplans (`Onboarding_Wizard_Fahrplan_Detail.md`) gegen den dokumentierten Funktionsstand (`HANDOVER-PM.md`, Stand 2026-07-20). Ziel: Umsetzbarkeit, Wiederverwendung vorhandener Funktionen, neue Funktionen, Komplexitäten — als Grundlage für die anschließende Aufgaben-/Epic-Definition. + +**Status-Legende:** ✅ Vorhanden (direkt nutzbar) · 🟡 Teilweise (erweitern) · 🟥 Neu (bauen) +**Aufwand:** S ≤ 1 Tag · M 2–4 Tage · L > 1 Woche (Entwicklung; Fachcontent separat) + +--- + +## 1. Gesamturteil + +**Der Wizard ist umsetzbar — und sitzt auf einem für dieses Vorhaben ungewöhnlich starken Fundament.** Rund zwei Drittel der fachlichen Bausteine existieren bereits produktiv (Assets/BIA, Risikoanalyse, Richtlinien-/Template-Engine mit Control-Mapping, importierter VDA-ISA-Katalog mit 316 Anforderungen/45 Controls, AL2/AL3-Schalter, Vier-Augen-Freigabe, Lieferanten-Reifegrad-/Gate-Logik, Coverage-Matrix, Audit-Log, Mandantenfähigkeit). + +Der Wizard ist damit **weniger „neues Modul" als vielmehr eine geführte Orchestrierung vorhandener Module** plus einige neue Quer­schnitts-Engines. Der eigentliche Aufwand liegt — wie der Fahrplan selbst richtig betont — **nicht in der Software, sondern im Fachcontent** (regelfähige Vorlagen, VDA-Risiko-Katalog, Umsetzungshinweise, Reifegrad-Logik). Das ist der kritische Pfad und zugleich die Stelle, an der die GEFIM-Projekt-DNA (~100 Projekte) zum Tragen kommt. + +**Drei Dinge müssen früh und sauber gebaut werden, sonst werden sie später teuer nachgezogen:** (1) ein generisches Aufgaben-Modul, (2) der generische Validierungs-Workflow, (3) der Regel-/Mapping-Layer. Sie sind die Klammer um alle Schritte. + +--- + +## 2. Querschnittsmechaniken (Kap. 2 des Fahrplans) + +| Mechanik | Status | Vorhanden (wiederverwendbar) | Neu zu bauen | Aufwand | Risiko | +|---|:--:|---|---|:--:|---| +| **2.1 Validierungs-Workflow** | 🟡 | Vier-Augen-Freigabe Richtlinien (Entwurf→In Freigabe→Freigegeben), Lieferanten-ISB-Reifegrad-Freigabe, RBAC, Audit-Log | **Generisches** Status-/Review-Modell über alle Objekttypen (Modul/Richtlinie/Risiko/Control-Bewertung), Rolle „externer Berater" als Validierer, Kommentare, „unbestätigt zählt nicht" in der Auswertung | M | Querschnitt — früh bauen, nicht anflanschen | +| **2.2 Umsetzungshinweise** | 🟡→🟥 | `implementation`-Feld je Anforderung im Katalog, Anwender-Handbuch (kuratiert, Deep-Links) | Strukturiertes Hinweis-Modell (org/tech/Nachweise/Vorlagen-Verweis/**Ressourcenindikation**), Scope-/Antwort-Filter, Inline-Panel | Backend S · FE S · **Content L** | Content-Flaschenhals (SME) | +| **2.3 Maßnahmen → Aufgaben-Modul** | 🟡 | Maßnahmen-Kanban (risikobezogen), berechnetes Restrisiko | **Generisches** Aufgaben-Objekt (Typ/Verantwortlich/Fälligkeit/Priorität/**Ressourcen**/Herkunft/Verknüpfung Control·Risiko·Dok·Asset), Auto-Vorschlag aus Triggern + Bestätigung | M–L | **Keystone** — alle Schritte hängen daran | +| **2.4 Audit-Trail & Versionierung** | 🟡 | Audit-Log vorhanden | Echte Versionierung (Richtlinien-Diff ist offen), Versionierung von Katalog/Templates/Risiko-Katalog + Instanz-Referenz + Update-Propagation | M–L | Verzahnt mit offener „Versionierung+Diff" & destruktivem Re-Import | + +--- + +## 3. Fachliche Bausteine / Datenobjekte (Kap. 3) + +| Baustein | Status | Vorhanden | Neu / Lücke | Aufwand | +|---|:--:|---|---|:--:| +| Control-Katalog VDA ISA | ✅ | Import 316 Anforderungen / 45 Controls, je Anforderung adressierbar, Typen MUSS/SOLL/HOHER/SEHR HOHER | Ggf. explizite AL2/AL3-Kennzeichnung je Anforderung sichtbar machen (Flags vorhanden) | S | +| Template-Bibliothek | ✅ | 28 Dokumente, Platzhalter/Variablen, optionale Klauseln via `{{#if}}`, Control-Verknüpfung, Freigabe | Regel-Tagging über Feature-Flags hinaus (Scope/Antwort-getrieben) | S–M | +| Upload eigener Dokumente | 🟡 | (geplant) Word-Upload als Block-Modell + Anhang, versioniert | Control-Zuordnung des Uploads in die Nachweislage; Upload selbst ist noch offen | M | +| Fakten-/Fragemodell | 🟡 | Variablen-Pflegestelle, Stammdaten (Settings) → ISMS-Variablen | **Dynamischer, bedingter Fragebogen** als wiederverwendbare Faktenobjekte | M | +| Risiko-Katalog | 🟡 | Bedrohungs-/Schwachstellen-Kataloge, Risikoregister, Control-Verknüpfung | Kuratierter **Standard-/VDA-Risiko-Katalog** (vordefiniert, erweiterbar) | Backend M · **Content L** | +| Regel-/Mapping-Layer | 🟡 | Handlebars-Flags, Variablen-Mapping, Lieferanten-Anforderungs-Engine (Schutzbedarf→Stufen) | **Generalisierung:** Antwort → betroffene Controls/Assets/Risiken (nicht nur Dokument-Klauseln) | L | +| Reifegrad-/Gap-Engine | 🟡 | Coverage-Matrix (Control↔Dokument), Lieferanten-Reifegrad-Freigabe, Gate→Risiko | Control-**Scoring aus Belegen** + Markierung offener Teilanforderungen | Backend M–L · SME M | + +--- + +## 4. Die neun Schritte (Kap. 4) + +| Schritt | Status | Trägt auf vorhandenem auf | Neu zu bauen | Aufwand | +|---|:--:|---|---|:--:| +| **1 Scoping** | 🟡 | AL2/AL3-Schalter (global + Override), TISAX-Level in Settings | Scope-Objekt (Prüfziele/Standorte/Geltungsbereich/Ausschlüsse) + **Filterung** der Control-/Template-/Risiko-Sets | FE S · Backend M | +| **2 Kontextaufnahme** | 🟡 | Stammdaten→Variablen | Geführter, **bedingter Fragebogen** + wiederverwendbare Faktenobjekte + Propagation | M | +| **3 Rollen & Verantwortlichkeiten** | 🟡 | RBAC/Rollen je Mandant, RACI-Matrix (Lieferanten) | ISMS-Rollenmodell (GF/ISB/DSB/IT), **Funktionstrennungs-Prüfung**, Rollen-Platzhalter in Dokumenten (ISB-Bestellung) | Backend M · FE S | +| **4 Richtlinien & VA** | ✅🟡 | Template-Tailoring (a) voll: variablenbasiert, Klausel-Ein/Ausblendung, Freigabe | (b) Upload+Control-Mapping (Upload offen); (c) „später erstellen" → Aufgabe (hängt an 2.3) | (a) ✅ · (b) M · (c) S | +| **5 Asset-Inventar** | ✅ | Assets & BIA: C/I/A, Schutzbedarf, Eigentümer, Vererbung, Abhängigkeiten, Risiko-Verknüpfung | „unvollständig/kein Eigentümer" → Aufgabe (Trigger) | S | +| **6 Risikomanagement** | ✅🟡 | 5×5-Heatmap, Register, Behandlung, Maßnahmen, Control-Verknüpfung | VDA-Risiko-Katalog-Auswahl; Maßnahme→Aufgabe (2.3); Methodik konfigurierbar (siehe Offen #2) | M | +| **7 Control-Zuordnung & Reifegrad** | 🟡→🟥 | Coverage-Matrix, Beleg-Verknüpfung, Lieferanten-Reifegrad-Muster | **Control-Assessment-Oberfläche** (SoA ist bisher Platzhalter) + Reifegrad-Selbsteinschätzung + Gap-Markierung je Teilanforderung | Backend L · FE L · SME L | +| **8 Gap- & Maßnahmenableitung** | 🟥 | Ergebnisse aus 6/7 | Aggregation/Dedup/Priorisierung → konsolidierte Gap-Liste (hängt an 2.3) | M | +| **9 Assessment-Readiness** | 🟥 | validierte Objekte, Coverage-Daten | Reifegrad-Dashboard + vorausgefüllte VDA-ISA-Katalogsicht + **Export** (koppelt an offenen DOCX/PDF-Export) | Backend M · FE L | +| **Wizard-Shell (implizit)** | 🟥 | — | Geführter Multi-Step-Flow: Zustand, Fortschritt, Gates, Wiederaufnahme, „bestätigt/unbestätigt"-Propagation | M–L | + +--- + +## 5. Was wirklich neu gebaut werden muss (verdichtete Liste) + +1. **Wizard-Shell / State-Machine** (Flow, Fortschritt, Gates, Resume). 🟥 M–L +2. **Generisches Aufgaben-Modul** (2.3) — Keystone. 🟡→ M–L +3. **Generischer Validierungs-Workflow** (2.1) inkl. externer-Berater-Rolle. 🟡→ M +4. **Regel-/Mapping-Layer generalisiert** (Antwort→Controls/Assets/Risiken). 🟡→ L +5. **Scope-Objekt + Filter-Engine** (Schritt 1). 🟥 M +6. **Dynamischer Fragebogen** (Schritt 2). 🟥 M +7. **ISMS-Rollenmodell + Funktionstrennung** (Schritt 3). 🟥 M +8. **Control-Assessment / Reifegrad-Gap-Engine** (Schritt 7, SoA-Surface). 🟥 L +9. **Gap-Konsolidierung** (Schritt 8). 🟥 M +10. **Assessment-Readiness-Dashboard + Export** (Schritt 9, koppelt an DOCX/PDF-Export). 🟥 L +11. **Umsetzungshinweis-Content-Modell + Inline-Panel** (2.2). 🟡→ Backend/FE S, Content L +12. **Versionierung/Diff + Update-Propagation** (2.4; löst zugleich offenen destruktiven Re-Import). 🟡→ M–L + +**Direkt wiederverwendbar (kaum/kein Neubau):** Assets/BIA · Risikoanalyse (Kern) · Richtlinien-Template-Engine · Control-Katalog VDA-ISA · AL2/AL3-Schalter · Vier-Augen-Freigabe (als Muster) · Coverage-Matrix · Lieferanten-Anforderungs-/Reifegrad-Engine (als Muster) · Audit-Log · Multi-Tenant/RBAC · Stammdaten→Variablen. + +--- + +## 6. Größte Komplexitäten & Risiken (priorisiert) + +1. **Fachcontent ist der kritische Pfad** (bestätigt der Fahrplan selbst): regelfähige Vorlagen, VDA-Risiko-Katalog, **Umsetzungshinweise je Teilanforderung**, Reifegrad-Logik. Muss **parallel und früh** von der Beratung erstellt werden — sonst blockiert er M3/M4/M5/M7. +2. **Regel-/Mapping-Engine (Generalisierung).** Heute: Klausel-Flags + Variablen + Lieferanten-Engine. Neu: eine Antwort steuert Dokument-Klauseln **und** Control-Relevanz **und** Risiko-/Asset-Bezug. Architektur-Kernrisiko — Regel-Syntax und Test­barkeit früh festzurren. +3. **Control-Assessment/Reifegrad (Schritt 7).** Das „SoA & Controls"-Modul ist bisher nur Platzhalter; hier entsteht die eigentliche Assessment-Oberfläche. Größter einzelner FE/Backend-Block. +4. **Versionierung & Update-Propagation.** Solange Re-Import destruktiv ist und Richtlinien keine echte Versionierung haben, sind laufende Kundeninstanzen bei Katalog-/Template-Updates gefährdet. Muss vor „Katalog lebt beim Kunden" gelöst sein. +5. **Keystones Aufgaben-Modul & Validierungs-Workflow** früh, sonst teurer Umbau (Schritte 3–9 hängen daran). +6. **Export/North-Star** (vorausgefüllter VDA-ISA-Katalog) koppelt an den offenen DOCX/PDF-Export. + +--- + +## 7. Antworten auf die offenen Entscheidungspunkte des Fahrplans (Kap. 7), PO-Sicht + +1. **Upload-Gap-Check:** Start mit **manueller Control-Zuordnung** (deckt sich mit dem bereits geplanten Word-Upload); automatischer Inhalt↔Anforderung-Abgleich später als KI-Ausbaustufe (koppelt an geplanten „KI-Wizard"). +2. **Risiko-Methodik:** **mandantenspezifisch konfigurierbar**, aber zuvor die zwei bestehenden Matrizen (5×5 Risikoanalyse / 4×4 FB-80-04 im Richtlinienmodul) **auf eine zentrale Skala vereinheitlichen** (steht bereits als offener Punkt). +3. **Versionierung/Propagation:** **nicht-destruktives Update mit Diff** und expliziter Übernahme je Instanz (löst zugleich den destruktiven Re-Import). Voraussetzung für „Katalog beim Kunden". +4. **Validierungs-Granularität:** **pro Objekt** (einzelne Richtlinie/Risiko/Control-Bewertung) **plus** Modul-Gate — die Freigabe-Logik ist heute schon objektbezogen (Richtlinien) und wird generalisiert. +5. **Aufgaben-Modul:** existiert **nur teilweise** (Maßnahmen-Kanban, risikobezogen) → **muss generalisiert werden**; die Task-Erzeugung ist mitzuplanen (Keystone). +6. **Reifegrad-Vorschlag:** **regelbasiert vorgeschlagen, mit Pflicht zur Bestätigung** durch den Bearbeiter (entspricht dem vorhandenen Lieferanten-Reifegrad-Freigabe-Muster). + +--- + +## 8. Empfohlene Reihenfolge (für die Aufgaben-Definition) + +Angelehnt an M1–M7 des Fahrplans, sortiert nach Abhängigkeit und Wiederverwendung: + +1. **Querschnitt-Keystones zuerst:** Aufgaben-Modul (2.3), Validierungs-Workflow (2.1), Versionierung/Diff (2.4), Wizard-Shell. *(sonst später teurer Umbau)* +2. **Regel-/Scope-Fundament:** Scope-Objekt + Filter (Schritt 1), Regel-/Mapping-Layer, Fragebogen (Schritt 2). +3. **Wiederverwendung einklinken:** Richtlinien (Schritt 4, größtenteils vorhanden), Assets (Schritt 5, vorhanden), Risiko (Schritt 6, Kern vorhanden + VDA-Katalog). +4. **Neuer Kern:** Control-Assessment/Reifegrad (Schritt 7), Gap-Konsolidierung (Schritt 8). +5. **Output:** Assessment-Readiness-Dashboard + Export (Schritt 9). +6. **Durchgängig parallel:** Fachcontent (SME/Beratung) + Umsetzungshinweise (2.2). + +--- + +## 9. Nächster Schritt +Auf dieser Basis die **Entwickler-Aufgaben als Epics/Stories** definieren — vorgeschlagene Epic-Schnitte: +**E1** Aufgaben-Modul · **E2** Validierungs-Workflow · **E3** Wizard-Shell & Navigation · **E4** Scope & Regel-/Mapping-Layer · **E5** Fragebogen/Fakten · **E6** ISMS-Rollen & Funktionstrennung · **E7** Richtlinien-Anbindung (Upload/Control-Mapping) · **E8** Risiko-Katalog & -Anbindung · **E9** Control-Assessment/Reifegrad-Gap · **E10** Gap-Konsolidierung · **E11** Assessment-Readiness/Export · **E12** Versionierung/Propagation · **E13** Umsetzungshinweise (Content+Panel) · **C1** Fachcontent (querlaufend). + +> Offen für die Feinspezifikation: Regel-Syntax, Aufgaben-Objekt-Schema, Reifegrad-Scoring-Formel, Export-Format des VDA-ISA-Katalogs. Diese vier zuerst festzurren — sie determinieren den Rest. diff --git a/docs/wizard-uebergabe/01_Planung/Wizard-Entwickler-Backlog.md b/docs/wizard-uebergabe/01_Planung/Wizard-Entwickler-Backlog.md new file mode 100644 index 0000000..7a00eb5 --- /dev/null +++ b/docs/wizard-uebergabe/01_Planung/Wizard-Entwickler-Backlog.md @@ -0,0 +1,133 @@ +# Onboarding-Wizard — Entwickler-Backlog (2 Full-Stack-Lanes, parallel auf `dev`) + +Grundlage: `Onboarding_Wizard_Fahrplan_Detail.md` (Berater), `STAND-dev-branch.md` (Ist-Stand `dev`, 2026-07-24), `Onboarding-Wizard-Machbarkeitsanalyse.md`. +Aufbau: **2 Entwickler**, je **vertikaler Feature-Slice** (BE+FE+Migration) auf eigenem **Feature-Branch unter `dev`**. Umfang: **kompletter Wizard**. Manueller Richtlinien-Upload: **UI/Modell jetzt, Datei-Speicher später** (Storage-Adapter gestubbt). + +> Fachliche Zulieferungen (SME/Berater) sind je Epic mit **🧩 SME** markiert und in `Berater-Anweisung-Fachcontent.md` als Arbeitspakete C1–C9 ausformuliert. + +--- + +## 0. Arbeitsmodell, Branching & Definition of Done + +**Branching** +- Basis-Branch: **`dev`** (nicht `main`). Alle Feature-Branches zweigen von `dev` ab, PR-Ziel ist `dev`. +- Namensschema: **`dev/<lane><n>-<slug>`** — z. B. `dev/a1-wizard-shell`, `dev/b2-regel-engine`. +- **Dev A = Lane A** („Flow, Governance & Bewertung"), **Dev B = Lane B** („Engines, Inhalte & Ausgabe"). +- Häufig auf `dev` rebasen (mind. täglich), kleine PRs je Epic, Review durch die jeweils andere Person. + +**Definition of Done (jede Story)** +- `npx tsc --noEmit` → `npm run lint` → `npm run build` grün (der `prebuild`-Guard-Check läuft mit). +- Neue Server-Action-Datei ist in **`scripts/check-module-guards.ts`** eingetragen (Modul-Key oder `EXEMPT`). +- Neues tenant-gebundenes Modell in **`TENANT_MODELS`** (`src/server/db.ts`) **und** RLS-Policy in der Migration. +- Migration erstellt (Prisma-7-Flow) inkl. manuell angehängtem **RLS-DO-Block**; läuft via `migrate deploy`. +- Wenn Seed/Vorlagenpaket berührt: `python3 seed/isms-vorlagenpaket-v2/_verify.py` → **OK**. +- Browser-Verifikation der Kern-Flows; Demo-Daten/Seed weiterhin lauffähig. + +**Geteilte „Hot Files" — nur koordiniert anfassen (Konflikt-Risiko):** +`prisma/schema.prisma` · Migrationsreihenfolge · `src/lib/modules.ts` · `scripts/check-module-guards.ts` · `src/server/db.ts` (`TENANT_MODELS`) · das Wizard-Shell-Step-Registry (Lane A liefert, Lane B registriert Steps). +→ Migrationen **nie gleichzeitig** ohne Absprache erzeugen; jede Lane hält ihre Migration isoliert und rebased vor dem Erstellen. + +--- + +## 1. Zuerst festzurren — Foundation-Contracts (gemeinsam, VOR den Lanes) + +Ein kurzer gemeinsamer Branch **`dev/foundation-contracts`** (1 Person federführend, andere reviewt), **zuerst nach `dev` gemergt**. Legt die vier Verträge fest, die alles andere determinieren: + +1. **Aufgaben-Objekt-Schema** — Erweiterung des bestehenden `Task`/`TaskComment` (heute Typ `policy_approval`) um: `type` (`document_create` / `evidence_provide` / `technical` / `organizational` / `validation`), `owner`, `dueDate`, `priority`, `status`, **`resources` (JSON: tool/budget/personnel/time)**, **`origin` (auslösender Schritt)**, polymorphe Verknüpfung (`control` / `risk` / `document` / `asset`). RLS wie gehabt. +2. **Objekt-Validierungs-Status** — einheitliches Enum `offen → in_bearbeitung → zur_validierung → validiert | zurueckgewiesen(+Kommentar)` als wiederverwendbares Feld/Mixin über Objekttypen; Rolle **`external_validator`** (externer Berater). +3. **Regel-/Mapping-DSL** — Vertrag: `Bedingung(Antwort/Scope/Flag) → Wirkung(Klausel ein/aus · Control relevant/irrelevant · Risiko/Asset-Bezug · Aufgabe)`. JSON-basiert, testbar; baut auf vorhandenen Handlebars-Flags + Lieferanten-Anforderungs-Engine auf. +4. **Assessment-Readiness-Export-Format** — Datenschema des vorausgefüllten VDA-ISA-Katalogs (Control → Teilanforderungen → Reifegrad/Belege/offene Punkte/Status „bestätigt|unbestätigt"). + +**Aufwand:** M (Schema-/Typ-Definitionen + Migration `tasks`-Erweiterung). **DoD:** Typen/Interfaces + Task-Migration gemergt, damit beide Lanes darauf bauen. + +--- + +## 2. Lane A — Dev A: „Flow, Governance & Bewertung" + +| Epic | Branch | Hängt ab von | Aufwand | 🧩 SME | +|---|---|---|---|:--:| +| **A1 Wizard-Shell & Navigation** | `dev/a1-wizard-shell` | Foundation | M–L | – | +| **A2 Scoping + AL2/AL3 zentral (Adminportal) + Scope-Filter** | `dev/a2-scoping-admin-al` | A1 | M | 🧩 C1 | +| **A3 Validierungs-Workflow generalisieren** | `dev/a3-validation-workflow` | Foundation, B1 | M | – | +| **A4 ISMS-Rollen & Funktionstrennung (Schritt 3)** | `dev/a4-isms-rollen` | A1, A3 | M | 🧩 C7 | +| **A5 Asset-Anbindung Wizard (Schritt 5, Reuse)** | `dev/a5-assets-step` | A1 | S | – | +| **A6 Risiko-Katalog & Anbindung (Schritt 6)** | `dev/a6-risiko-katalog` | A1, B2 | M–L | 🧩 C4 | +| **A7 Control-Assessment & Reifegrad/Gap (Schritt 7, SoA)** | `dev/a7-control-assessment` | A2, B1, B2, B5 | L | 🧩 C5, C6 | +| **A8 Gap-Konsolidierung (Schritt 8)** | `dev/a8-gap-konsolidierung` | A6, A7, B1 | M | 🧩 C8 | + +**A1 — Wizard-Shell & Navigation.** Neuer Bereich `src/app/(app)/onboarding/**` + `src/server/actions/onboarding.ts` (in `check-module-guards.ts` registrieren; neues Modul `onboarding` in `src/lib/modules.ts`). Multi-Step-State-Machine mit Fortschritt, **Gates** (Schritt „validiert" bevor weiter), **Wiederaufnahme**, und einem **Step-Registry**, in das Lane B ihre Schritt-Komponenten einklinkt (klare Datei-Trennung je Schritt). Persistenter Wizard-Fortschritt je Mandant. *Akzeptanz:* Flow ist resumierbar; Gates blockieren korrekt; Schritte sind als eigenständige Module registrierbar. + +**A2 — Scoping + AL2/AL3 zentral im Adminportal.** (Explizite Anforderung.) Der **AL2/AL3-Schalter wird zentral im Superadmin-/Adminportal** gesetzt (`src/app/(platform)/admin/**` + `src/server/actions/admin.ts`/`platform.ts`) als Teil der Mandanten-Kern-Config — **einzige Quelle der Wahrheit**. Schritt 1 (Scoping) liest ihn **read-only** (nur Superadmin ändert), plus Prüfziele/Standorte/Geltungsbereich/Ausschlüsse → **Scope-Objekt**. Scope filtert nachgelagert Control-/Template-/Risiko-Sets (an vorhandene Coverage-Filter-Logik nach Assessment-Level andocken). *Akzeptanz:* AL nur im Adminportal änderbar; Änderung propagiert in Coverage/Zusatzanforderungen; nicht relevante Controls/Templates ausgeblendet. **🧩 C1** (AL2/AL3-Kennzeichnung + Prüfziel-Zuordnung je Control). + +**A3 — Validierungs-Workflow generalisieren.** Den bestehenden Vier-Augen-Freigabe-/Task-Mechanismus (`policy_approval`) zu einem **generischen Objekt-Review** über alle Typen ausbauen (Modul/Richtlinie/Risiko/Control-Bewertung): Status-Feld (Foundation #2), Reviewer-Zuweisung inkl. **externer Berater**, Kommentare, „unbestätigt zählt nicht" in Auswertungen. Wiederverwendet `src/server/actions/tasks.ts` + `submitForApproval`. *Akzeptanz:* jedes Objekt trägt Review-Status; nur „validiert" zählt als bestätigt; externer Validierer-Rolle testbar. + +**A4 — ISMS-Rollen & Funktionstrennung (Schritt 3).** ISMS-Rollenmodell (GF/ISB/DSB/IT) auf Basis vorhandener RBAC/RACI; **Funktionstrennungs-Prüfung** (z. B. ISB ≠ IT); Rollen-Platzhalter in Dokumente (ISB-Bestellung aus Vorlage). Konflikt → Hinweis/Aufgabe (A3/B1). *Akzeptanz:* Funktionstrennungs-Konflikt wird erkannt und als Aufgabe ausgewiesen. **🧩 C7**. + +**A5 — Asset-Anbindung Wizard (Schritt 5).** Dünne Wizard-Schicht auf das bestehende Assets/BIA-Modul (C/I/A, Schutzbedarf, Eigentümer, Abhängigkeiten sind vorhanden). Trigger „Inventar unvollständig / kein Eigentümer" → Aufgabe (B1). *Akzeptanz:* Wizard nutzt Bestands-Assets; Trigger erzeugt Aufgabe. + +**A6 — Risiko-Katalog & Anbindung (Schritt 6).** Bewertungs-/Register-Kern existiert (5×5, Behandlung, Control-Verknüpfung). Neu: **kuratierter Standard-/VDA-Risiko-Katalog** (Auswahl + eigene Ergänzung), Verknüpfung Asset/Control, Maßnahme→Aufgabe (B1). *Akzeptanz:* VDA-geforderte Risiken auswählbar; inakzeptables Risiko hat Behandlung; Maßnahmen erzeugen Aufgaben. **🧩 C4** (Kataloginhalt + Standardmaßnahmen). + +**A7 — Control-Assessment & Reifegrad/Gap (Schritt 7, SoA).** Größter Block: baut die bislang fehlende **SoA-/Control-Oberfläche**. Je Control: Beleg-Verknüpfung (Dok/Risiko/Asset), **Reifegrad-Selbsteinschätzung** mit regelbasiertem Vorschlag (aus Belegen) **+ Pflichtbestätigung** (Muster: Lieferanten-Reifegrad-Freigabe), Markierung offener Teilanforderungen; unter Ziel → Aufgabe. Nutzt Coverage-Daten + Foundation-Export-Schema. *Akzeptanz:* jede relevante Teilanforderung adressiert; Reifegradvorschlag nachvollziehbar an Belege gekoppelt. **🧩 C5** (Reifegrad-Logik), **🧩 C6** (Umsetzungshinweis-Content, via B5). + +**A8 — Gap-Konsolidierung (Schritt 8).** Aggregation/Dedup/Priorisierung (Muss/AL3 = hoch) aus Schritt 6+7 zu einer konsolidierten Gap-/Maßnahmenliste, abgeglichen mit Aufgaben (B1). *Akzeptanz:* keine Dopplungen; jeder offene Punkt hat Priorität + ggf. Aufgabe. **🧩 C8** (Priorisierungslogik/Quick-Wins). + +--- + +## 3. Lane B — Dev B: „Engines, Inhalte & Ausgabe" + +| Epic | Branch | Hängt ab von | Aufwand | 🧩 SME | +|---|---|---|---|:--:| +| **B1 Aufgaben-Modul erweitern** | `dev/b1-tasks-erweiterung` | Foundation | M | – | +| **B2 Regel-/Mapping-Layer** | `dev/b2-regel-engine` | Foundation | L | 🧩 C2 | +| **B3 Fragebogen/Fakten (Schritt 2)** | `dev/b3-fragebogen` | A1, B2 | M | 🧩 C2 | +| **B4 Richtlinien: Import-bei-Aktivierung + manueller Upload + Control-Mapping (Schritt 4 + Menü)** | `dev/b4-richtlinien-import-upload` | Foundation | M–L | 🧩 C3 | +| **B5 Umsetzungshinweise (Content-Modell + Inline-Panel)** | `dev/b5-umsetzungshinweise` | A1 | S (Code) | 🧩 C6 | +| **B6 Versionierung/Propagation** | `dev/b6-versionierung` | B4 | M–L | – | +| **B7 Assessment-Readiness & Export (Schritt 9)** | `dev/b7-readiness-export` | A7, A8 | L | 🧩 C9 | + +**B1 — Aufgaben-Modul erweitern.** Das generische `Task`-Modell (heute `policy_approval`) um die Foundation-Felder erweitern; **Auto-Generierung** aus Triggern (Schritt 3/4/6/7/8, Zurückweisung) als **Vorschlag mit Bestätigung**; Ressourcenfelder editierbar; Verknüpfungen Control/Risiko/Dok/Asset; Anzeige/Filter im bestehenden Modul „Aufgaben" (`src/app/(app)/tasks/`). *Akzeptanz:* Trigger erzeugt Aufgabenvorschlag mit korrekten Verknüpfungen/Ressourcen; Bestätigung übernimmt. + +**B2 — Regel-/Mapping-Layer.** Umsetzung der DSL (Foundation #3) als testbare Engine `src/lib/rules/**`: Antwort/Scope/Flag → Klausel-Ein/Ausblendung (Handlebars-Flags erweitern), betroffene Controls/Assets/Risiken, Aufgaben-Trigger. Isoliert + unit-getestet. *Akzeptanz:* Regelauswertung deterministisch, mit Testfällen belegt; Änderung einer Antwort propagiert sichtbar. **🧩 C2** (Antwort→Wirkung-Mapping). + +**B3 — Fragebogen/Fakten (Schritt 2).** Dynamischer, **bedingter Fragebogen**; Antworten als **wiederverwendbare Faktenobjekte** (an vorhandene zentrale Variablen/Stammdaten andocken, ohne die Sperre der zentralen Variablen zu verletzen). Bedingte Sichtbarkeit über B2. *Akzeptanz:* Antworten wiederverwendbar; Änderung propagiert in abhängige Objekte/Platzhalter. **🧩 C2** (Fragenkatalog). + +**B4 — Richtlinien: Import-bei-Aktivierung + manueller Upload + Control-Mapping.** (Explizite Anforderung.) Zwei Wege: +- **(a) Vorlagen-Import bei Modul-Aktivierung:** Wird das **Richtlinien-Modul im Superadmin/Adminportal aktiviert**, wird das Vorlagenpaket **mandantenweit importiert** — die vorhandene **nicht-destruktive** Logik (`prisma/import-policies.ts`, Diff/Upsert/`archivedAt`) als **serverseitig auslösbare Aktion/Job** kapseln (statt nur CLI/Seed). Zusätzlich Button „Vorlagen importieren/aktualisieren" (Admin bzw. `/policies`). Idempotent, Änderungsreport. +- **(b) Manueller Upload eigener Richtlinien direkt im Menü `/policies`:** Einstiegspunkt + Metadaten-/Block-Modell + **Control-Zuordnung** jetzt bauen; **Datei-Persistenz über einen Storage-Adapter-Interface stubben** (echtes Storage-Backend = Folge-Epic **S1**, außerhalb dieses Batches). Upload erfasst Datei-Referenz/Platzhalter + Control-Mapping in die Nachweislage. *Akzeptanz:* Modul-Aktivierung importiert Vorlagen nicht-destruktiv; unter `/policies` existiert „Eigene Richtlinie hochladen" mit Control-Zuordnung; Storage-Adapter ist gekapselt und später ohne UI-Änderung verdrahtbar. **🧩 C3** (regelfähige Vorlagen-Auszeichnung). + +**B5 — Umsetzungshinweise (Content-Modell + Inline-Panel).** Strukturiertes Hinweis-Modell (org/tech/Nachweise/Vorlagen-Verweis/**Ressourcenindikation**), Scope-/Antwort-Filter (B2), kontextsensitives Inline-Panel an Teilanforderungen/Risiken/Templates. Code klein — **Inhalt ist der Aufwand**. *Akzeptanz:* passende Hinweise werden nach Scope/Antworten gefiltert eingeblendet; führen bei Maßnahme zu Aufgabe (B1). **🧩 C6**. + +**B6 — Versionierung/Propagation.** Versionierung von Katalog/Templates/Risiko-Katalog + **Instanz-Referenz auf genutzte Version** + **Diff & gesteuerte Übernahme** bei Updates (löst zugleich den heute noch offenen Richtlinien-Diff und flankiert den nicht-destruktiven Re-Import). *Akzeptanz:* laufende Kundeninstanz bekommt bei Update einen Diff und übernimmt kontrolliert; nichts wird still überschrieben. + +**B7 — Assessment-Readiness & Export (Schritt 9).** Reifegrad-Dashboard je Kapitel/gesamt, vorausgefüllte **VDA-ISA-Katalogsicht**, Maßnahmenplan; „bestätigt vs. unbestätigt" nach Validierungsstatus (A3); **Export** (koppelt an den offenen DOCX/PDF-Export). *Akzeptanz:* Kennzahlen stimmen mit Einzelbewertungen; Export vollständig/nachvollziehbar. **🧩 C9** (Auswertungs-/Interpretationstexte, Export-Layout). + +--- + +## 4. Sequenz / Meilensteine (2 Lanes im Takt) + +| Takt | Dev A (Lane A) | Dev B (Lane B) | Gate | +|---|---|---|---| +| **M0** | Foundation-Contracts (gemeinsam) | Foundation-Contracts (gemeinsam) | Contracts + `tasks`-Migration auf `dev` | +| **M1** | A1 Wizard-Shell | B1 Tasks-Erweiterung · B2 Regel-Engine (Kern) | Shell + Task-API stehen | +| **M2** | A2 Scoping/Admin-AL | B4 Richtlinien-Import/Upload · B3 Fragebogen | AL zentral · Import läuft | +| **M3** | A3 Validierung · A4 Rollen | B5 Umsetzungshinweise | Review generisch | +| **M4** | A5 Assets · A6 Risiko-Katalog | B6 Versionierung | Katalog/Risiko nutzbar | +| **M5** | A7 Control-Assessment (SoA) | (Puffer/Review A7) · Start B7 | Kern-Bewertung steht | +| **M6** | A8 Gap-Konsolidierung | B7 Readiness & Export | North-Star: Readiness-Export | + +**Kürzester Pfad zur Assessment-Readiness:** M0→M1→M2→…→M6. Governance (A3/B1/B5/B6) läuft bewusst mit, nicht am Ende. + +--- + +## 5. Explizite Anforderungen (Kurz-Referenz) +- **AL2/AL3 zentral im Adminportal:** → **A2** (einzige Quelle im Superadmin/Admin; Scoping liest read-only; treibt Coverage/AL3-Zusatzanforderungen). +- **Richtlinien-Vorlagen-Import bei Modul-Aktivierung + manueller Upload im Menü:** → **B4** (Import nicht-destruktiv on-enable; manueller Upload jetzt als UI/Modell/Control-Mapping, Datei-Speicher via Storage-Adapter später = Folge-Epic **S1**). + +## 6. Außerhalb dieses Batches (Folge-Epics) +- **S1 Storage-Backend** (Coolify-Volume/MinIO) — schaltet echten Datei-Upload (B4b, Netzplan REG-NET, Nachweis-Upload) scharf. +- **Paket 4** (SMTP/Einladung), **NIS2-Modul**, **Admin Phase 2** (Impersonation/Plan-Limits) — unverändert im Backlog. + +--- + +## 7. Nächster Schritt +Foundation-Contracts (Abschnitt 1) gemeinsam finalisieren und mergen → dann Lanes starten. Fachliche Zulieferung C1–C9 parallel anstoßen (siehe `Berater-Anweisung-Fachcontent.md`), sonst werden C2/C3/C4/C5/C6 zum kritischen Pfad für A2/A6/A7 und B2/B3/B4/B5. diff --git a/docs/wizard-uebergabe/01_Planung/Wizard-Stories.md b/docs/wizard-uebergabe/01_Planung/Wizard-Stories.md new file mode 100644 index 0000000..db16b44 --- /dev/null +++ b/docs/wizard-uebergabe/01_Planung/Wizard-Stories.md @@ -0,0 +1,174 @@ +# Onboarding-Wizard — Story-Backlog (umsetzungsreif, mit Fachcontent C1–C9) + +Basis: `Wizard-Entwickler-Backlog.md` (2 Lanes) + Fachcontent `Fachcontent_Wizard_C1-C9` + Dev-Stand `dev` (2026-07-24). +Jede Story: **ID · Titel · (Lane/Branch) · User Story · Akzeptanzkriterien · Technik/Dateien · Fachcontent · Abhängigkeit**. + +**Konventionen (für alle Stories):** DoD wie im Backlog (§0: `tsc`+`lint`+`build`/Guard-Check, `TENANT_MODELS`+RLS, Migration+RLS-DO-Block, `_verify.py`→OK bei Seed-Änderung, Browser-Verifikation). Story-Größe: S/M/L. +**Fachcontent-Referenzen:** C1 = Scoping/AL-Tabelle (412 Anf.), C2 = Fragenkatalog+Wirkung, C3 = Vorlagen-Annotation, C4 = Risikokatalog (39 Risiken), C5 = Reifegrad R0–R3, C6 = Umsetzungshinweise (~397 Blöcke), C7 = Rollen/FT-01…06, C8 = Priorisierung/Dedup, C9 = Auswertung/Export. + +--- + +## F — Foundation-Contracts (`dev/foundation-contracts`, gemeinsam, zuerst mergen) + +### F1 — Aufgaben-Objekt-Schema erweitern (M) +**Als** Entwickler **möchte ich** das bestehende `Task`/`TaskComment`-Modell um Wizard-Felder erweitern, **damit** alle Schritte Aufgaben einheitlich erzeugen. +- **AK:** `Task` besitzt `type` (`document_create|evidence_provide|technical|organizational|validation`), `owner`, `dueDate`, `priority`, `status`, `resources` (JSON: tool/budget/personnel/time), `origin` (Schritt), polymorphe Verknüpfung `control|risk|document|asset`. Bestehender Typ `policy_approval` bleibt lauffähig. +- **Technik:** `prisma/schema.prisma` (`Task`), Migration `tasks_wizard_fields`, `TENANT_MODELS`+RLS, `src/server/actions/tasks.ts` erweitern (in `check-module-guards.ts` registriert). +- **Fachcontent:** C2 §8 (Task-Trigger), C8 (Priorität/Dedup als Feldsemantik). + +### F2 — Einheitlicher Objekt-Validierungsstatus + externe-Validierer-Rolle (M) +**Als** ISB/Berater **möchte ich** jedes bewertbare Objekt gleich validieren. +- **AK:** wiederverwendbares Status-Feld `offen|in_bearbeitung|zur_validierung|validiert|zurueckgewiesen(+Kommentar)`; Rolle `external_validator` in RBAC; „unbestätigt zählt nicht" ist als Query-Helfer verfügbar. +- **Technik:** Mixin/Enum in `schema.prisma`; RBAC-Recht; baut auf `submitForApproval`/`tasks.ts`. +- **Fachcontent:** C5 (Validierungsstatus je Beleg), C9 (bestätigt/unbestätigt). + +### F3 — Regel-/Mapping-DSL-Vertrag (M) +**Als** Entwickler **möchte ich** einen testbaren Regel-Vertrag, **damit** Antworten/Scope/Flags Wirkungen auslösen. +- **AK:** JSON-Schema `Bedingung(Antwort|Scope|Flag) → Wirkung(Klausel|Control|Risiko|Asset|Aufgabe)`; Referenz-Testfälle aus C2 §5 (Q-FEAT-01…10) grün. +- **Technik:** `src/lib/rules/dsl.ts` (Typen) + Unit-Test-Harness. Noch keine UI. +- **Fachcontent:** C2 (Wirkungsmatrix), C1 (Scope-Bedingung-Spalte). + +### F4 — Wizard-Variablen/Flags erweitern (`variables.schema.json`) (S) +**Als** Content-Owner **möchte ich** neue Flags/Variablen registriert haben, **damit** `_verify.py` sie kennt. +- **AK:** `FLAG_PROTOTYPE_PROTECTION`, `FLAG_ISB_EXTERNAL`, `FLAG_ISB_INTERNAL` + fehlende `ROLE_*`/`TECH_*` aus C2 ergänzt; `python3 _verify.py` → **OK**. +- **Technik:** `seed/isms-vorlagenpaket-v2/variables.schema.json`. +- **Fachcontent:** C0 (offene Punkte 2), C2 §3–6, C7 §3. **Abh.:** vor B2/B3/B4/A4. + +--- + +## Lane A — Dev A + +### A1 — Wizard-Shell & Navigation (`dev/a1-wizard-shell`) +**A1-1 Step-Registry & State-Machine (L).** Multi-Step-Flow mit Fortschritt, Gates, Wiederaufnahme; Schritte als registrierbare Module. +- **AK:** Fortschritt je Mandant persistent; ein Gate blockiert „weiter", bis das Vorgänger-Objekt `validiert` ist (F2); Steps sind per Registry einklinkbar (Lane B liefert Step-Inhalte). +- **Technik:** `src/app/(app)/onboarding/**`, `src/server/actions/onboarding.ts`, neues Modul `onboarding` in `src/lib/modules.ts`; Migration `onboarding_progress`. +**A1-2 Fortschritts-/Status-Dashboard-Kachel (S).** Kachel „Onboarding-Fortschritt" analog vorhandener Dashboard-Kachel. + +### A2 — Scoping + AL2/AL3 zentral im Adminportal (`dev/a2-scoping-admin-al`) +**A2-1 AL2/AL3 zentral im Admin/Superadmin (M).** *(Explizite Anforderung.)* +- **AK:** Der Assessment-Level (AL2/AL3) wird **ausschließlich** im Admin-/Superadmin-Portal je Mandant gesetzt (einzige Quelle); im Scoping read-only; treibt bestehende Coverage-Filter + `FLAG_HIGH/VERY_HIGH_PROTECTION`. +- **Technik:** `src/app/(platform)/admin/**`, `src/server/actions/admin.ts`/`platform.ts`; Mandanten-`/settings` verliert die Änderungs-Kompetenz (nur Anzeige). +**A2-2 Scope-Objekt + Filter-Engine (M).** +- **AK:** Scoping erfasst Prüfziele (IS/Prototyp/Datenschutz), Standorte, Geltungsbereich, Ausschlüsse → Scope-Objekt; Filter blendet Anforderungen nach **AL + Flag + Prüfziel** exakt gemäß C1 aus (z. B. `HOCH` nur bei `FLAG_HIGH_PROTECTION`; 8.x nur bei Prototyp). +- **Technik:** Scope-Modell + `src/lib/scope-filter.ts`; Import der C1-Tabelle als Datenquelle je Anforderung. +- **Fachcontent:** **C1** (AL2/AL3 + Prüfziel + Scope-Bedingung je Anforderung, 412 Zeilen). **Abh.:** F3, A1. + +### A3 — Validierungs-Workflow generalisieren (`dev/a3-validation-workflow`) +**A3-1 Generisches Objekt-Review (M).** +- **AK:** Richtlinie/Risiko/Control-Bewertung/Modul tragen Review-Status (F2); Reviewer-Zuweisung inkl. `external_validator`; Kommentare; Auswertung zählt nur `validiert`. +- **Technik:** Ausbau `src/server/actions/tasks.ts` + `submitForApproval`; generische Review-Komponente. +- **Fachcontent:** C9 §1 (bestätigt/unbestätigt). **Abh.:** F1, F2. + +### A4 — ISMS-Rollen & Funktionstrennung (`dev/a4-isms-rollen`) +**A4-1 Rollenmodell + Platzhalter (M).** +- **AK:** Rollen `ROLE_MANAGEMENT/ISB/IT_LEAD/HR_LEAD/DPO` erfassbar (aus C2 Abschnitt B), befüllen Vorlagen-Platzhalter; ISB-Bestellung aus Vorlage generierbar. +- **Technik:** Rollen-Modell; Anbindung zentrale Variablen (`src/lib/policy-variables.ts`). +**A4-2 Funktionstrennungs-Prüfung FT-01…06 (M).** +- **AK:** Regeln **FT-01…FT-06** aus C7 implementiert; Konflikt/Lücke → Hinweis + Aufgabe (F1); Option „Trennung herstellen" **oder** „kompensierende Kontrolle dokumentieren". +- **Fachcontent:** **C7** (Rollen, FT-Regeln, `VA-00_ISB-Bestellung.md`, Flags `FLAG_ISB_EXTERNAL/INTERNAL`). **Abh.:** F4, A3. + +### A5 — Asset-Anbindung Wizard (`dev/a5-assets-step`) +**A5-1 Asset-Schritt auf Bestandsmodul (S).** +- **AK:** Schritt 5 nutzt vorhandenes Assets/BIA (C/I/A, Schutzbedarf, Eigentümer); Trigger „unvollständig/kein Eigentümer" → Aufgabe (F1). Keine Doppel-Datenhaltung. + +### A6 — Risiko-Katalog & Anbindung (`dev/a6-risiko-katalog`) +**A6-1 Risiko-Katalog-Datenmodell + Import (M).** +- **AK:** 39 Katalog-Risiken (11 Kategorien) importiert mit ID `R-<KAT>-<nr>`, Controls, Asset-Typen, Standardmaßnahmen, Default `E/S`; erweiterbar; „nicht anwendbar"-Begründung möglich. +- **Technik:** Risiko-Katalog-Seed + Auswahl-UI im vorhandenen Risikomodul; 5×5 wie C4. +**A6-2 Maßnahme → Aufgabe + Restrisiko (M).** +- **AK:** ausgewähltes Risiko → Bewertung (5×5) → Behandlung → Standardmaßnahme erzeugt Aufgabe (F1), verknüpft Risiko+Control; Restrisiko > Akzeptanz erfordert dokumentierte Akzeptanz (VA-09). +- **Fachcontent:** **C4** (Katalog + Bewertungslogik + Standardmaßnahmen). **Abh.:** F1, B2. + +### A7 — Control-Assessment & Reifegrad/Gap (`dev/a7-control-assessment`, SoA) +**A7-1 Control-/SoA-Oberfläche (L).** +- **AK:** je relevantem Control: Belege verknüpfen (Dok/Risiko/Asset), Teilanforderungen sichtbar (aus C1/`mapping.json`), offene Teilanforderungen markiert; Inline-Umsetzungshinweise (B5/C6). +**A7-2 Reifegrad-Engine R0–R3 + Pflichtbestätigung (L).** +- **AK:** Reifegrad-Vorschlag exakt nach **C5**-Regeln (R0/R1a-c/R2/R3, Sonderfälle, Aktualitätsregel ≤12 Mon., Deckelung bei Widerspruch); Vorschlag ist **an Belege gekoppelt und nachvollziehbar**; Bearbeiter-Bestätigung Pflicht; Zielreifegrad nach C5 §3 (AL2→2, AL3→3, HOCH/SEHR HOCH→3). +- **AK:** Reifegrad < Ziel / offene Teilanforderung → Aufgabe (F1). +- **Technik:** `src/app/(app)/soa/**` (bislang Platzhalter) + `src/server/actions/soa.ts`; Reifegrad-Berechnung `src/lib/maturity.ts` (unit-getestet gegen C5-Beispiele). +- **Fachcontent:** **C5** (Reifegradlogik), **C6** (Umsetzungshinweise). **Abh.:** A2, B1, B2, B5. + +### A8 — Gap-Konsolidierung (`dev/a8-gap-konsolidierung`) +**A8-1 Aggregation + Dedup + Priorisierung (M).** +- **AK:** offene Punkte aus Schritt 6/7 zusammengeführt; **Dedup-Schlüssel** (Control+Teilanforderung / verknüpfte Aufgabe) nach C8 §2; Priorität **Hoch/Mittel/Niedrig** nach C8 §1 mit Zusatzsortierung (betroffene Controls, Risikohöhe, Aufwand); keine Dopplungen; jeder Punkt hat Priorität + ggf. Aufgabe. +**A8-2 Quick-Win-Kennzeichnung (S).** +- **AK:** Quick-Win-Kriterien aus C8 §3; im Maßnahmenplan hervorgehoben („erst Quick-Wins"). +- **Fachcontent:** **C8**. **Abh.:** A6, A7, B1. + +--- + +## Lane B — Dev B + +### B1 — Aufgaben-Modul erweitern (`dev/b1-tasks-erweiterung`) +**B1-1 Auto-Generierung mit Bestätigung (M).** +- **AK:** Trigger aus Schritt 3/4/6/7/8 + Zurückweisung erzeugen **Aufgabenvorschlag** (Typ/Verknüpfung/Ressourcen aus F1); Bearbeiter bestätigt/verwirft; Anzeige/Filter im Modul „Aufgaben" (`src/app/(app)/tasks/`). +- **Fachcontent:** C2 §8 (konkrete Trigger). **Abh.:** F1. + +### B2 — Regel-/Mapping-Engine (`dev/b2-regel-engine`) +**B2-1 Engine-Kern + Klausel-Flags (L).** +- **AK:** DSL (F3) ausgewertet: Antwort/Scope/Flag → Klausel ein/aus (Handlebars-Flags), Control-Relevanz, Risiko-/Asset-Bezug, Aufgabe; deterministisch, unit-getestet gegen **C2** Q-FEAT-01…10. +- **Technik:** `src/lib/rules/**`; koppelt an vorhandene `{{#if FLAG}}`-Renderer + Lieferanten-Anforderungs-Engine. +**B2-2 Propagation bei Antwortänderung (M).** +- **AK:** Änderung einer Antwort propagiert sichtbar in abhängige Objekte/Platzhalter/Controls. +- **Fachcontent:** **C2** (Wirkungsmatrix), C1 (Scope-Bedingungen). **Abh.:** F3, F4. + +### B3 — Fragebogen/Fakten (`dev/b3-fragebogen`) +**B3-1 Dynamischer, bedingter Fragebogen (M).** +- **AK:** Abschnitte A–F aus C2 mit Antworttypen + Anzeige-Bedingungen; Antworten als wiederverwendbare Faktenobjekte; Baseline-Fragen (E) als vorbelegte Defaults aus `Technische-Sicherheits-Baseline.md` (nur bestätigen). +- **AK:** zentrale Variablen bleiben serverseitig gesperrt (nur `/settings`), Fragebogen respektiert das. +- **Technik:** `src/app/(app)/onboarding/steps/context/**` (im A1-Registry); Faktenmodell + Migration. +- **Fachcontent:** **C2** (Fragen A–F, Baseline-Defaults). **Abh.:** A1, B2, F4. + +### B4 — Richtlinien: Import-bei-Aktivierung + manueller Upload + Control-Mapping (`dev/b4-richtlinien-import-upload`) +**B4-1 Vorlagen-Import bei Modul-Aktivierung (M).** *(Explizite Anforderung.)* +- **AK:** Aktiviert der Superadmin das Richtlinien-Modul, wird das Paket mandantenweit **nicht-destruktiv** importiert (bestehende Logik `prisma/import-policies.ts` als Server-Action/Job gekapselt); Button „Vorlagen importieren/aktualisieren" in Admin und `/policies`; idempotent, Änderungsreport. +**B4-2 Manueller Upload eigener Richtlinien im Menü (M).** *(Explizite Anforderung; Storage später.)* +- **AK:** unter `/policies` „Eigene Richtlinie hochladen" mit **Pflicht-Control-Zuordnung** (Multi-Select Control-Katalog, optional Anforderungs-IDs, siehe C3 §4); Metadaten/Block-Modell angelegt; Datei-Persistenz über gestubbtes **Storage-Adapter-Interface** (echtes Backend = Folge-Epic S1); Zuordnung fließt als `<!-- REQ -->`-Äquivalent in die Nachweislage (Schritt 7). +**B4-3 Proto/DS-Vorlagen P01/D01 + mapping.json (M).** +- **AK:** neue Vorlagen `P01_Prototypenschutz.md` (+ `VA-20`) und `D01_Datenschutz.md` nach C3-Konvention angelegt; `mapping.json`-Einträge im gleichen Schema (8.x/9.x); `FLAG_PROTOTYPE_PROTECTION` genutzt; `_verify.py` (um neue Anker erweitert) → **OK**. +- **Fachcontent:** **C3** (Annotationskonvention + P01/D01), C1/C6 (Dekomposition 8.x/9.x). **Abh.:** F4. + +### B5 — Umsetzungshinweise (`dev/b5-umsetzungshinweise`) +**B5-1 Hinweis-Datenmodell + Import (S Code).** +- **AK:** Hinweis-Objekt je Teilanforderung mit Feldern **organisatorisch/technisch/Nachweise/Vorlage/Ressourcen/AL-Filter**; Import der ~397 C6-Blöcke; Baseline-Referenzen (`BL-*`) statt harter Werte. +**B5-2 Kontextsensitives Inline-Panel (S).** +- **AK:** Panel an Teilanforderung/Risiko/Template; gefiltert nach Scope/Antworten (B2) und AL; Ressourcen-Hinweis mit Beschaffungsbedarf → Aufgabe (F1). +- **Fachcontent:** **C6** (Hinweise), C0 offener Punkt 3 (Baseline-Codes vor Verdrahtung gegen `Technische-Sicherheits-Baseline.md` normalisieren). **Abh.:** A1. + +### B6 — Versionierung/Propagation (`dev/b6-versionierung`) +**B6-1 Versionierung Katalog/Templates/Risiko + Instanz-Referenz (M).** +- **AK:** Kundeninstanz referenziert genutzte Template-/Katalog-Version; Änderungen erzeugen Diff. +**B6-2 Gesteuerte Übernahme (Diff) (M).** +- **AK:** bei Update erhält die Instanz einen Diff mit kontrollierter Übernahme; nichts wird still überschrieben (ergänzt nicht-destruktiven Re-Import + löst offenen Richtlinien-Diff). **Abh.:** B4. + +### B7 — Assessment-Readiness & Export (`dev/b7-readiness-export`) +**B7-1 Reifegrad-Dashboard + Interpretationstexte (M).** +- **AK:** Aggregation je Kapitel/gesamt (Ø, „unbestätigt zählt nicht"); Textbänder nach C9 §1; Kennzahlen (Anteil bestätigt, offene Punkte je Priorität, Abdeckung je Prüfziel); dynamische „nächste Schritte" (C9 §2). +**B7-2 VDA-ISA-Katalog-Export (L).** +- **AK:** Export-Layout exakt nach **C9 §3** (Felder Control-ID/Frage/Reifegrad/Status/Umsetzungsbeschreibung MUSS→SOLL→HOCH→SEHR HOCH/Belege/offene Punkte); Reihenfolge IS→Proto→DS; „unbestätigt" markiert; **XLSX** (Katalog+Kennzahlen) + DOCX/PDF-Management-Summary (koppelt an bestehenden Export); Zusatzartefakte (Maßnahmenplan, Nachweisregister) nach C9 §4. +- **Fachcontent:** **C9**. **Abh.:** A7, A8. + +--- + +## Content-Integration & offene Fachpunkte (aus C0) + +| ID | Story | Owner | Abh. | +|---|---|---|---| +| **X1** | Neue `FLAG_*`/Variablen in `variables.schema.json` (siehe F4) | B (mit SME) | vor B2/B3/B4/A4 | +| **X2** | P01/D01 + `VA-20` Vorlagen + `mapping.json`-Einträge (B4-3) | B (mit SME) | C3 | +| **X3** | Baseline-`BL-*`-Codes aus C6 gegen `Technische-Sicherheits-Baseline.md` normalisieren | B5 (mit SME) | vor B5-Verdrahtung | +| **X4** | ISB-Freigabe aller neuen/angepassten Fachtexte (VA/Richtlinien/P01/D01) | ISB (fachlich, kein Code) | vor Produktivsetzung | + +--- + +## Sprint-Vorschlag (2 Lanes) + +- **Sprint 0:** F1–F4 (gemeinsam) → mergen. +- **Sprint 1:** A1 · B1 + B2-1. +- **Sprint 2:** A2 (+C1) · B4 (+C3) + B3 (+C2). +- **Sprint 3:** A3 · A4 (+C7) · B5 (+C6). +- **Sprint 4:** A5 · A6 (+C4) · B6. +- **Sprint 5:** A7 (+C5/C6). +- **Sprint 6:** A8 (+C8) · B7 (+C9). + +> „Definition of Ready" je Story: zugehöriges C-Paket eingespielt und (wo Seed) `_verify.py` → **OK**. Fehlt der Fachcontent, bleibt die Story blockiert (kritischer Pfad: C2 → C1/C3 → C5/C6). diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C0_README-Fachcontent-Uebersicht.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C0_README-Fachcontent-Uebersicht.md new file mode 100644 index 0000000..9ef5d44 --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C0_README-Fachcontent-Uebersicht.md @@ -0,0 +1,35 @@ +# Fachcontent-Zulieferung C1–C9 — Übersicht + +Fachliche Zulieferung (SME/Berater) für den Onboarding-Wizard, gemäß `BeraterAnweisungFachcontent.md` und `WizardEntwicklerBacklog.md`. Alle Pakete sind ID-konsistent zum bestehenden Vorlagenpaket `isms-vorlagenpaket-v2` (`mapping.json`, `variables.schema.json`, Baseline `BL-*`). Prüfziele: Informationssicherheit (Paketbasis), Prototypenschutz (8.x) und Datenschutz (9.x) als Erweiterung. + +## Lieferpakete + +| WP | Datei | Schaltet frei (Backlog) | Inhalt | +|---|---|---|---| +| **C1** | `C1_Scoping-AL-Pruefziel.md` | A2 | AL2/AL3-Kennzeichnung + Prüfziel + Scope-Bedingung je Anforderung — **412 Anforderungen** (316 IS + 72 Proto + 24 DS) | +| **C2** | `C2_Fragenkatalog-Wirkung.md` | B2, B3 | Fragenkatalog (A–F) + Antwort→Wirkung (Variable/Flag/Control/Risiko/Aufgabe), gekoppelt an `variables.schema.json` | +| **C3** | `C3_Vorlagen-Annotation.md` | B4 | Annotationskonvention (REQ/IMPL-Anker, `{{#if FLAG}}`, Baseline-Variablen), Ist-Bestätigung (`_verify.py → OK`), Erweiterung P01/D01 | +| **C4** | `C4_Risikokatalog.md` | A6 | Standard-/VDA-Risiko-Katalog (**39 Risiken, 11 Kategorien**) mit Controls, Assets, Standardmaßnahmen, Default-5×5-Einschätzung | +| **C5** | `C5_Reifegradlogik.md` | A7 | Generische Beleg→Reifegrad-Regel + control-spezifische Tabelle (alle 45 IS-Controls + Proto/DS-Gruppen), Zielreifegrad, Offene-Punkt-Kriterium | +| **C6** | `C6_Umsetzungshinweise.md` | B5, A7 | Umsetzungshinweise je Teilanforderung (**~397 Blöcke über 79 Controls**): org/tech, Nachweise, Vorlage, Ressourcen, AL-Filter | +| **C7** | `C7_Rollen-Funktionstrennung.md` | A4 | Soll-Rollenmodell, Funktionstrennungs-Regeln (FT-01…06), ISB-Bestellungs-Vorlage im Paket-Stil | +| **C8** | `C8_Priorisierung-Gap.md` | A8 | Prioritätsregeln (Hoch/Mittel/Niedrig), Dedup-Kriterien, Quick-Win-Definition | +| **C9** | `C9_Auswertung-Export.md` | B7 | Reifegrad-Interpretationstexte, nächste Schritte, VDA-ISA-Export-Layout (bestätigt/unbestätigt) | + +## Konsistenz-Anker + +- **Anforderungs-IDs** = `mapping.json`-IDs (z. B. `4.1.2-H1`); Proto/DS neu im gleichen Schema (`8.1.1-M1`, `9.1.1-M1`). +- **Flags/Variablen** = `variables.schema.json` (Single Source of Truth). Neue Flags (`FLAG_PROTOTYPE_PROTECTION`, `FLAG_ISB_EXTERNAL/INTERNAL`) sind in C3/C7 vermerkt und dort zuerst zu ergänzen. +- **Technische Werte** = Baseline `BL-*` (C6 referenziert, nie hart kodiert). +- **Vorlagenpaket** unverändert; `python3 seed/isms-vorlagenpaket-v2/_verify.py` → **OK**. + +## Offene Punkte / Abhängigkeiten für die Umsetzung + +1. **Proto/DS-Vorlagen** (`P01`, `D01`) und zugehörige `mapping.json`-Einträge sind noch anzulegen (C3 Abschnitt 3) — die Anforderungsdekomposition + Hinweise (C1/C5/C6) liegen bereits vor. +2. **Neue `FLAG_*`** vor Nutzung in `variables.schema.json` ergänzen, damit `_verify.py` sie kennt. +3. **Baseline-IDs in C6**: Agenten haben teils sprechende `BL-*`-Codes ergänzt, die über den dokumentierten Satz (BL-IAM/CRY/OPS/NET/EP/PHY/HR/SUP/DEL/GOV/PROJ) hinausgehen — vor Verdrahtung gegen `Technische-Sicherheits-Baseline.md` normalisieren. +4. **ISB-Freigabe** der neuen/angepassten Fachtexte ist der abschließende fachliche Schritt (steht im Backlog offen auf `dev`). + +## Reihenfolge (kritischer Pfad) + +C2 → C1/C3 (schalten B2/B3 und A2/B4 frei) → C4/C5/C6 (A6/A7/B5) → C7/C8/C9. Entspricht der Meilenstein-Sequenz M0–M6 des Backlogs. diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C1_Scoping-AL-Pruefziel.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C1_Scoping-AL-Pruefziel.md new file mode 100644 index 0000000..85b94a4 --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C1_Scoping-AL-Pruefziel.md @@ -0,0 +1,444 @@ +# C1 — Scoping-Grundlage: AL2/AL3-Kennzeichnung + Prüfziel-Zuordnung je Anforderung + +> **Schaltet frei:** A2 (Scoping / Admin-AL / Scope-Filter). **Grundlage:** `mapping.json` (Informationssicherheit, 316 Anforderungen) + Prototypenschutz/Datenschutz-Dekomposition (Erweiterung). + +## Methodik (Zuordnungslogik) + +Der Assessment-Level (AL) wird **zentral im Adminportal** gesetzt (Backlog A2) und ist read-only im Scoping. Die Zuordnung folgt der VDA-ISA-/TISAX-Systematik: + +- **MUSS / SOLL** → Bestandteil von **AL2 und AL3** (Grundabsicherung; SOLL über `FLAG_INCLUDE_SHOULD` für Ziel-Reifegrad 3). +- **HOCH** (Zusatz hoher Schutzbedarf) → relevant bei **hohem Schutzbedarf** (typisch AL3), Flag `FLAG_HIGH_PROTECTION`. +- **SEHR HOCH** (Zusatz sehr hoher Schutzbedarf) → relevant bei **sehr hohem Schutzbedarf** (AL3), Flag `FLAG_VERY_HIGH_PROTECTION`. +- **Prüfziel** steuert, ob ein ganzes Kapitel überhaupt im Scope ist (Informationssicherheit / Prototypenschutz / Datenschutz). +- **Scope-Bedingung** = das Feature-Flag bzw. die Bedingung aus `mapping.json` (`condition`); ist keine gesetzt, gilt „immer im Scope" (sobald das Prüfziel aktiv ist). + +Der Scope-Filter (A2) blendet je nach AL + Flags + Prüfziel die nicht relevanten Anforderungen aus. Spalte „Scope-Bedingung" ist maschinenlesbar an die `FLAG_*` aus `variables.schema.json` gekoppelt. + +## Prüfziel Informationssicherheit (316 Anforderungen) + +| Control | Anforderungs-ID | Typ | AL2 | AL3 | Prüfziel | Scope-Bedingung (Flag) | +|---|---|---|:--:|:--:|---|---| +| 1.1.1 | 1.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.1.1 | 1.1.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.1.1 | 1.1.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.1.1 | 1.1.1-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.1.1 | 1.1.1-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.1.1 | 1.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.1.1 | 1.1.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.1.1 | 1.1.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.1.1 | 1.1.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.2.1 | 1.2.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.1 | 1.2.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.1 | 1.2.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.1 | 1.2.1-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.1 | 1.2.1-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.1 | 1.2.1-M6 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.2 | 1.2.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.2 | 1.2.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.2 | 1.2.2-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.2 | 1.2.2-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.2 | 1.2.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.2.2 | 1.2.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.2.2 | 1.2.2-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.2.3 | 1.2.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.2.3 | 1.2.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.2.3 | 1.2.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.2.3 | 1.2.3-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.2.3 | 1.2.3-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.3.1 | 1.3.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.1 | 1.3.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.1 | 1.3.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.2 | 1.3.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.2 | 1.3.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.2 | 1.3.2-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.2 | 1.3.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.3 | 1.3.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.3 | 1.3.3-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.3 | 1.3.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.3 | 1.3.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.3 | 1.3.3-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.3 | 1.3.3-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.4 | 1.3.4-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.4 | 1.3.4-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.3.4 | 1.3.4-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.4 | 1.3.4-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.4 | 1.3.4-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.4 | 1.3.4-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.4 | 1.3.4-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.3.4 | 1.3.4-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 1.4.1 | 1.4.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.4.1 | 1.4.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.4.1 | 1.4.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.4.1 | 1.4.1-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.4.1 | 1.4.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.4.1 | 1.4.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.4.1 | 1.4.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.4.1 | 1.4.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.5.1 | 1.5.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.1 | 1.5.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.1 | 1.5.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.1 | 1.5.1-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.1 | 1.5.1-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.1 | 1.5.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.5.2 | 1.5.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.2 | 1.5.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.5.2 | 1.5.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.1 | 1.6.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.1 | 1.6.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.1 | 1.6.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-S6 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.1 | 1.6.1-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 1.6.2 | 1.6.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.2 | 1.6.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.2 | 1.6.2-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.2 | 1.6.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.2 | 1.6.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.2 | 1.6.2-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.2 | 1.6.2-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.2 | 1.6.2-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.2 | 1.6.2-H3 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.2 | 1.6.2-H4 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.2 | 1.6.2-H5 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.2 | 1.6.2-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 1.6.3 | 1.6.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.3 | 1.6.3-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.3 | 1.6.3-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 1.6.3 | 1.6.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.3 | 1.6.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.3 | 1.6.3-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.3 | 1.6.3-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.3 | 1.6.3-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.3 | 1.6.3-S6 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 1.6.3 | 1.6.3-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.3 | 1.6.3-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.3 | 1.6.3-H3 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.3 | 1.6.3-H4 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.3 | 1.6.3-H5 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 1.6.3 | 1.6.3-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 2.1.1 | 2.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.1 | 2.1.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.1 | 2.1.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.1 | 2.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.1 | 2.1.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.2 | 2.1.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.2 | 2.1.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.2 | 2.1.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.2 | 2.1.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.2 | 2.1.2-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.3 | 2.1.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.3 | 2.1.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.3 | 2.1.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.3 | 2.1.3-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.3 | 2.1.3-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.3 | 2.1.3-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.3 | 2.1.3-S6 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.4 | 2.1.4-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 2.1.4 | 2.1.4-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.4 | 2.1.4-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 2.1.4 | 2.1.4-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 3.1.1 | 3.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 3.1.1 | 3.1.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 3.1.1 | 3.1.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 3.1.1 | 3.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 3.1.1 | 3.1.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 3.1.1 | 3.1.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 3.1.1 | 3.1.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 3.1.1 | 3.1.1-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 3.1.1 | 3.1.1-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 3.1.4 | 3.1.4-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 3.1.4 | 3.1.4-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 3.1.4 | 3.1.4-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 4.1.1 | 4.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.1 | 4.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.1 | 4.1.1-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 4.1.2 | 4.1.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.2 | 4.1.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.2 | 4.1.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.2 | 4.1.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.2 | 4.1.2-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.2 | 4.1.2-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 4.1.2 | 4.1.2-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 4.1.3 | 4.1.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-M6 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-M7 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.1.3 | 4.1.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S10 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S6 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S7 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S8 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.1.3 | 4.1.3-S9 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.2.1 | 4.2.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.2.1 | 4.2.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 4.2.1 | 4.2.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.2.1 | 4.2.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.2.1 | 4.2.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.2.1 | 4.2.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.2.1 | 4.2.1-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 4.2.1 | 4.2.1-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 4.2.1 | 4.2.1-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 4.2.1 | 4.2.1-V2 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.1.1 | 5.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.1.1 | 5.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.1.1 | 5.1.1-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.1.2 | 5.1.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.1.2 | 5.1.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.1.2 | 5.1.2-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.1.2 | 5.1.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.1.2 | 5.1.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.1.2 | 5.1.2-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.1.2 | 5.1.2-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.1.2 | 5.1.2-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.1 | 5.2.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.1 | 5.2.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.1 | 5.2.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.1 | 5.2.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.1 | 5.2.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.1 | 5.2.1-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.2 | 5.2.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.2 | 5.2.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.2 | 5.2.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.3 | 5.2.3-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.3 | 5.2.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S6 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S7 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.3 | 5.2.3-S8 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.4 | 5.2.4-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.4 | 5.2.4-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.4 | 5.2.4-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.4 | 5.2.4-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.4 | 5.2.4-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.4 | 5.2.4-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.4 | 5.2.4-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.4 | 5.2.4-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.4 | 5.2.4-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.4 | 5.2.4-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.4 | 5.2.4-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.5 | 5.2.5-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.5 | 5.2.5-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.5 | 5.2.5-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.5 | 5.2.5-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.5 | 5.2.5-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.5 | 5.2.5-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.6 | 5.2.6-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.6 | 5.2.6-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.6 | 5.2.6-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.6 | 5.2.6-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.6 | 5.2.6-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.6 | 5.2.6-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.6 | 5.2.6-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.6 | 5.2.6-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.6 | 5.2.6-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.6 | 5.2.6-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.7 | 5.2.7-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.7 | 5.2.7-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.7 | 5.2.7-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.7 | 5.2.7-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.7 | 5.2.7-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.8 | 5.2.8-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.8 | 5.2.8-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.8 | 5.2.8-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.8 | 5.2.8-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.8 | 5.2.8-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-H3 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-H4 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-H5 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-H6 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-H7 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-V2 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.8 | 5.2.8-V3 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.9 | 5.2.9-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.9 | 5.2.9-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.2.9 | 5.2.9-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.2.9 | 5.2.9-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.9 | 5.2.9-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.2.9 | 5.2.9-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.9 | 5.2.9-V2 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.2.9 | 5.2.9-V3 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.3.1 | 5.3.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.1 | 5.3.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.1 | 5.3.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.1 | 5.3.1-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.1 | 5.3.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.1 | 5.3.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.1 | 5.3.1-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.1 | 5.3.1-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.1 | 5.3.1-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.1 | 5.3.1-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 5.3.2 | 5.3.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.2 | 5.3.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.2 | 5.3.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.2 | 5.3.2-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.2 | 5.3.2-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 5.3.3 | 5.3.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.4 | 5.3.4-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.4 | 5.3.4-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 5.3.4-KI | 5.3.4-KI-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.4-KI | 5.3.4-KI-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.4-KI | 5.3.4-KI-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 5.3.4-KI | 5.3.4-KI-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.1 | 6.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.1 | 6.1.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.1 | 6.1.1-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.1 | 6.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.1 | 6.1.1-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.1 | 6.1.1-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.1 | 6.1.1-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.1 | 6.1.1-H3 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.1 | 6.1.1-V1 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 6.1.1 | 6.1.1-V2 | SEHR HOCH | – | Ja | Informationssicherheit | `FLAG_VERY_HIGH_PROTECTION` | +| 6.1.2 | 6.1.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.2 | 6.1.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.2 | 6.1.2-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.2 | 6.1.2-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.2 | 6.1.2-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.2 | 6.1.2-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.2 | 6.1.2-S3 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.2 | 6.1.2-S4 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.2 | 6.1.2-S5 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.3 | 6.1.3-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.3 | 6.1.3-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.3 | 6.1.3-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.3 | 6.1.3-M4 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.3 | 6.1.3-M5 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 6.1.3 | 6.1.3-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.3 | 6.1.3-S2 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 6.1.3 | 6.1.3-H1 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.3 | 6.1.3-H2 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.3 | 6.1.3-H3 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.3 | 6.1.3-H4 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 6.1.3 | 6.1.3-H5 | HOCH | – | Ja | Informationssicherheit | `FLAG_HIGH_PROTECTION` | +| 7.1.1 | 7.1.1-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 7.1.1 | 7.1.1-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 7.1.1 | 7.1.1-S1 | SOLL | Ja | Ja | Informationssicherheit | `FLAG_INCLUDE_SHOULD` | +| 7.1.2 | 7.1.2-M1 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 7.1.2 | 7.1.2-M2 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | +| 7.1.2 | 7.1.2-M3 | MUSS | Ja | Ja | Informationssicherheit | immer im Scope | + +## Prüfziel Prototypenschutz (72 Anforderungen) — Erweiterung + +| Control | Anforderungs-ID | Typ | AL2 | AL3 | Prüfziel | Scope-Bedingung (Flag) | +|---|---|---|:--:|:--:|---|---| +| 8.1.1 | 8.1.1-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.1 | 8.1.1-S1 | SOLL | Ja | Ja | Prototypenschutz | `FLAG_INCLUDE_SHOULD` | +| 8.1.2 | 8.1.2-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.2 | 8.1.2-S1 | SOLL | Ja | Ja | Prototypenschutz | `FLAG_INCLUDE_SHOULD` | +| 8.1.3 | 8.1.3-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.3 | 8.1.3-S1 | SOLL | Ja | Ja | Prototypenschutz | `FLAG_INCLUDE_SHOULD` | +| 8.1.3 | 8.1.3-S2 | SOLL | Ja | Ja | Prototypenschutz | `FLAG_INCLUDE_SHOULD` | +| 8.1.4 | 8.1.4-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.4 | 8.1.4-S1 | SOLL | Ja | Ja | Prototypenschutz | `FLAG_INCLUDE_SHOULD` | +| 8.1.4 | 8.1.4-S2 | SOLL | Ja | Ja | Prototypenschutz | `FLAG_INCLUDE_SHOULD` | +| 8.1.4 | 8.1.4-H1 | HOCH | – | Ja | Prototypenschutz | `FLAG_HIGH_PROTECTION` | +| 8.1.5 | 8.1.5-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.5 | 8.1.5-H1 | HOCH | – | Ja | Prototypenschutz | `FLAG_HIGH_PROTECTION` | +| 8.1.6 | 8.1.6-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.6 | 8.1.6-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.6 | 8.1.6-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.7 | 8.1.7-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.7 | 8.1.7-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.7 | 8.1.7-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.7 | 8.1.7-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.8 | 8.1.8-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.1.8 | 8.1.8-H1 | HOCH | – | Ja | Prototypenschutz | `FLAG_HIGH_PROTECTION` | +| 8.2.1 | 8.2.1-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.1 | 8.2.1-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.1 | 8.2.1-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.1 | 8.2.1-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.2 | 8.2.2-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.2 | 8.2.2-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.2 | 8.2.2-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.2 | 8.2.2-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.2 | 8.2.2-M5 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.2 | 8.2.2-M6 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M5 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M6 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.3 | 8.2.3-M7 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.4 | 8.2.4-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.4 | 8.2.4-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.4 | 8.2.4-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.5 | 8.2.5-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.5 | 8.2.5-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.5 | 8.2.5-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.6 | 8.2.6-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.6 | 8.2.6-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.6 | 8.2.6-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.6 | 8.2.6-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.6 | 8.2.6-M5 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.7 | 8.2.7-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.2.7 | 8.2.7-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.3.1 | 8.3.1-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.3.1 | 8.3.1-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.3.1 | 8.3.1-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.3.1 | 8.3.1-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.3.2 | 8.3.2-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.1 | 8.4.1-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.1 | 8.4.1-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.1 | 8.4.1-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.2 | 8.4.2-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.2 | 8.4.2-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.3 | 8.4.3-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.3 | 8.4.3-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.4.3 | 8.4.3-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.1 | 8.5.1-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.1 | 8.5.1-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.1 | 8.5.1-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.2 | 8.5.2-M1 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.2 | 8.5.2-M2 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.2 | 8.5.2-M3 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | +| 8.5.2 | 8.5.2-M4 | MUSS | Ja | Ja | Prototypenschutz | Prüfziel Prototypenschutz aktiv | + +> Hinweis Scope Prototypenschutz: Prüfziel bezieht sich in der aktuellen Konfiguration auf **Prototypenteile/-komponenten**; Controls 8.4.x (Test-/Erprobung) und 8.5.x (Ausstellungen/Film) sind per Scope-Regel `n.a.` und werden ausgeblendet. + +## Prüfziel Datenschutz (24 Anforderungen) — Erweiterung + +| Control | Anforderungs-ID | Typ | AL2 | AL3 | Prüfziel | Scope-Bedingung (Flag) | +|---|---|---|:--:|:--:|---|---| +| 9.1.1 | 9.1.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.2.1 | 9.2.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.2.1 | 9.2.1-M2 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.2.1 | 9.2.1-M3 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.2.1 | 9.2.1-M4 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.2.1 | 9.2.1-M5 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.2.1 | 9.2.1-M6 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.3.1 | 9.3.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.4.1 | 9.4.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.4.1 | 9.4.1-M2 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.5.1 | 9.5.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.5.2 | 9.5.2-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.5.2 | 9.5.2-M2 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.5.3 | 9.5.3-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.5.3 | 9.5.3-M2 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.5.3 | 9.5.3-M3 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.6.1 | 9.6.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.6.2 | 9.6.2-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.6.2 | 9.6.2-M2 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.6.2 | 9.6.2-M3 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.7.1 | 9.7.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.7.2 | 9.7.2-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.8.1 | 9.8.1-M1 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | +| 9.8.1 | 9.8.1-M2 | MUSS | Ja | Ja | Datenschutz | Prüfziel Datenschutz aktiv (`FLAG_PERSONAL_DATA`) | diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C2_Fragenkatalog-Wirkung.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C2_Fragenkatalog-Wirkung.md new file mode 100644 index 0000000..e97b77c --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C2_Fragenkatalog-Wirkung.md @@ -0,0 +1,110 @@ +# C2 — Fragenkatalog + Antwort→Wirkung-Mapping + +> **Schaltet frei:** B2 (Regel-/Mapping-Engine) und B3 (Fragebogen, Schritt 2). **Kritischer Pfad.** +> **Grundlage:** `variables.schema.json` (Single Source of Truth der Wizard-Variablen und `FLAG_*`), `mapping.json` (`condition`-Flags je Anforderung), `Technische-Sicherheits-Baseline.md` (`BL-*`-Parameter). + +## 1. Prinzip + +Jede Frage erzeugt eine **Wirkung** auf genau vier Kanäle (DSL-Vertrag aus dem Backlog, Foundation #3): + +1. **Variable/Platzhalter** — füllt einen `{{NAME}}`-Wert (z. B. `ORG_NAME`, `MFA_SCOPE`). +2. **Feature-Flag** — setzt ein `FLAG_*` true/false, das `{{#if FLAG_X}}`-Blöcke in Vorlagen und die Control-Relevanz steuert. +3. **Control/Risiko-Bezug** — schaltet Controls in den Scope und schlägt Katalog-Risiken (C4) vor. +4. **Aufgabe** — erzeugt bei bestimmten Antworten einen Aufgabenvorschlag (Aufgaben-Modul). + +Antworttypen: `text`, `single-select`, `multi-select`, `boolean`, `number/duration`. Baseline-Parameter (Abschnitt E) sind **vorbelegte Defaults** aus der Baseline; die Frage dient nur der Bestätigung/Anpassung, nicht der Ersteingabe. + +Anzeige-Bedingungen referenzieren zuvor gesetzte Flags (bedingter Fragebogen). + +--- + +## 2. Abschnitt A — Organisation & Geltungsbereich + +| Frage-ID | Frage | Antworttyp | Anzeige-Bedingung | Wirkung | +|---|---|---|---|---| +| Q-ORG-01 | Vollständiger Name der Organisation? | text | immer | Variable `ORG_NAME` | +| Q-ORG-02 | Kurzname/Abkürzung? | text | immer | Variable `ORG_SHORT` | +| Q-ORG-03 | Geltungsbereich – Kurzlabel? | text | immer | Variable `ISMS_SCOPE` | +| Q-ORG-04 | Geltungsbereich – Beschreibung (Standorte, Bereiche, Systeme, Ausschlüsse)? | text (lang) | immer | Variable `ISMS_SCOPE_DESCRIPTION`; speist Scope-Objekt (Schritt 1) | +| Q-ORG-05 | Verarbeitet die Organisation personenbezogene Daten? | boolean | immer | Flag `FLAG_PERSONAL_DATA`; schaltet Prüfziel Datenschutz (9.x) + Controls 7.1.2 · Risiken R-DSGVO-* | +| Q-ORG-06 | Werden Prototypen/schutzbedürftige Entwicklungsobjekte verarbeitet? | boolean | immer | schaltet Prüfziel Prototypenschutz (8.x); bei „nein" 8.x ausgeblendet | + +## 3. Abschnitt B — Rollen (→ Schritt 3, Paket C7) + +| Frage-ID | Frage | Antworttyp | Anzeige-Bedingung | Wirkung | +|---|---|---|---|---| +| Q-ROLE-01 | Oberste Leitung (Name/Funktion)? | text | immer | Variable `ROLE_MANAGEMENT` | +| Q-ROLE-02 | Informationssicherheitsbeauftragte(r)/CISO? intern/extern? | text + single-select | immer | Variable `ROLE_ISB`; Funktionstrennungsprüfung (C7); bei fehlend → Aufgabe „ISB bestellen" | +| Q-ROLE-03 | IT-Leitung / IT-Verantwortung (intern/extern)? | text | immer | Variable `ROLE_IT_LEAD`; Input Funktionstrennung ISB≠IT (C7) | +| Q-ROLE-04 | Personalleitung? | text | immer | Variable `ROLE_HR_LEAD` | +| Q-ROLE-05 | Datenschutzbeauftragte(r)? | text | `FLAG_PERSONAL_DATA` | Variable `ROLE_DPO` | + +## 4. Abschnitt C — Governance & Betriebsrahmen + +| Frage-ID | Frage | Antworttyp | Anzeige-Bedingung | Wirkung | +|---|---|---|---|---| +| Q-GOV-01 | Name des eingesetzten ISMS-Tools? | text | immer | Variable `TOOL_NAME` | +| Q-GOV-02 | Ticket-/Workflow-System (Dokumentationsort)? | text | immer | Variable `TOOL_TICKET` (BL-IAM-07, BL-OPS-02/09) | +| Q-GOV-03 | Verzeichnis-/IAM-System? | text | immer | Variable `TOOL_IAM` (BL-IAM-06/07) | +| Q-GOV-04 | Revisions-/Prüfzyklus? | single-select (jährlich/…) | immer | Variable `REVIEW_CYCLE` (BL-HR-01, BL-GOV-01) | +| Q-GOV-05 | Ziel-Reifegrad – SOLL-Anforderungen einbeziehen? | boolean (Default ja) | immer | Flag `FLAG_INCLUDE_SHOULD`; blendet alle `[SOLL]`-Blöcke ein/aus | + +## 5. Abschnitt D — Feature-Fragen (steuern `FLAG_*`, Klauseln, Controls, Risiken) + +Diese Fragen sind der Kern der Regel-Engine: jede Antwort blendet Vorlagenklauseln ein/aus, schaltet Controls in den Scope und schlägt Risiken vor. + +| Frage-ID | Frage | Antworttyp | Anzeige-Bedingung | Wirkung (Flag · Klausel/Control · Risiko/Aufgabe) | +|---|---|---|---|---| +| Q-FEAT-01 | Schutzbedarf im Scope – höchste Stufe? (normal / hoch / sehr hoch) | single-select | immer | `FLAG_HIGH_PROTECTION` (hoch|sehr hoch), `FLAG_VERY_HIGH_PROTECTION` (sehr hoch), abgeleitet `FLAG_ELEVATED_PROTECTION`; blendet `[HOCH]`/`[SEHR HOCH]`-Anforderungen + `-elev`-Umsetzungstexte ein | +| Q-FEAT-02 | Werden Cloud-Dienste genutzt? | boolean | immer | `FLAG_CLOUD_USED`; R12-Klauseln + Controls 5.3.2/5.3.4/6.1.3; Risiken R-CLOUD-* | +| Q-FEAT-03 | Werden KI-/GenAI-Dienste genutzt? | boolean | immer | `FLAG_AI_USED`; R12-KI-Klauseln + Control 5.3.4-KI · VA-11; Risiko R-AI-* | +| Q-FEAT-04 | Produktions-/OT-Umgebung vorhanden? | boolean | immer | `FLAG_OT_USED`; BL-NET-01 OT-Segmentierung; Risiken R-OT-* | +| Q-FEAT-05 | Eigene Software-Entwicklung? | boolean | immer | `FLAG_DEV_INHOUSE`; R11-Klauseln + Controls 5.3.1 · VA-16; Risiko R-DEV-* | +| Q-FEAT-06 | Mobiles Arbeiten / Homeoffice zugelassen? | boolean | immer | `FLAG_MOBILE_WORK`; R06-Klauseln + Control 2.1.4 | +| Q-FEAT-07 | Mobile Endgeräte / Datenträger im Einsatz? | boolean | immer | `FLAG_MOBILE_DEVICES`; R06/BL-EP-*; Control 3.1.4; Risiko R-PHY-mobile | +| Q-FEAT-08 | Eigene PKI / Zertifikatsverwaltung? | boolean | immer | `FLAG_CRYPTO_PKI`; BL-CRY-05 PKI-Klausel; Control 5.1.1 | +| Q-FEAT-09 | Externe IT-Dienstleister genutzt? | boolean | immer | `FLAG_EXTERNAL_IT`; R13-Klauseln + Controls 6.1.1/6.1.3 · VA-10; Risiko R-SUP-*; bei „ja" → Aufgabe „Dienstleister-Selbstauskunft einholen" | +| Q-FEAT-10 | Zugriff auf Kundensysteme (z. B. OEM)? | boolean | immer | `FLAG_CUSTOMER_SYSTEMS`; Klauseln „Konten in Kundensystemen" in R08/R13 (Controls 4.1.3/4.2.1/6.1.x) | + +## 6. Abschnitt E — Technische Baseline (Defaults bestätigen/anpassen) + +Vorbelegt aus `Technische-Sicherheits-Baseline.md`. Je Frage wird der Default angezeigt; Änderung schreibt die zugehörige Variable. Anzeige gruppiert; nur relevante bei gesetztem Flag. + +| Frage-ID | Frage (Parameter) | Variable / Baseline-ID | Anzeige-Bedingung | +|---|---|---|---| +| Q-BL-01 | Passwort-Mindestlänge / Komplexität / Rotation | `PW_MIN_LENGTH`,`PW_COMPLEXITY`,`PW_ROTATION` (BL-IAM-01) | immer | +| Q-BL-02 | MFA-Geltungsbereich | `MFA_SCOPE` (BL-IAM-02) | immer | +| Q-BL-03 | Sitzungs-Timeout | `SESSION_TIMEOUT` (BL-IAM-03) | immer | +| Q-BL-04 | Kontosperrung | `ACCOUNT_LOCKOUT` (BL-IAM-04) | immer | +| Q-BL-05 | Rezertifizierungs-Frequenz | `RECERT_FREQ` (BL-IAM-05) | immer | +| Q-BL-06 | Mindest-TLS / zulässige Algorithmen | `TLS_MIN`,`CRYPTO_ALGO` (BL-CRY-01/02) | immer | +| Q-BL-07 | Patch-SLAs (kritisch/hoch/standard) | `PATCH_SLA_CRIT/HIGH/STD` (BL-OPS-01) | immer | +| Q-BL-08 | Schwachstellenscan-Frequenz | `VULN_SCAN_FREQ` (BL-OPS-02) | immer | +| Q-BL-09 | Malware-Update-Frequenz | `MALWARE_UPDATE` (BL-OPS-03) | immer | +| Q-BL-10 | Log-Aufbewahrung | `LOG_RETENTION` (BL-OPS-04) | immer | +| Q-BL-11 | Backup-Schema / Aufbewahrung / Testfrequenz | `BACKUP_SCHEME/RETENTION/TEST_FREQ` (BL-OPS-05/06) | immer | +| Q-BL-12 | Penetrationstest-Frequenz | `PENTEST_FREQ` (BL-OPS-08) | `FLAG_ELEVATED_PROTECTION` | +| Q-BL-13 | Eingesetzte Lösungen: MFA/Malware/Backup/SIEM/MDM/VPN | `TECH_MFA/MALWARE/BACKUP/SIEM/MDM/VPN` | jeweils bei zugehörigem Flag | +| Q-BL-14 | Krypto-Standardvorgabe | `TECH_CRYPTO` (BL-CRY-02) | immer | + +## 7. Abschnitt F — Dokument-Metadaten + +| Frage-ID | Frage | Variable | +|---|---|---| +| Q-DOC-01 | Dokument-Version (Default 1.0) | `DOC_VERSION` | +| Q-DOC-02 | Dokument-Datum | `DOC_DATE` | +| Q-DOC-03 | Dokument-Status (Entwurf/In Freigabe/Freigegeben) | `DOC_STATUS` | + +--- + +## 8. Aufgaben-Trigger aus Antworten (Auszug) + +| Auslösende Antwort | Aufgabe (Typ) | +|---|---| +| Q-ROLE-02 „ISB nicht benannt" | `organizational` – ISB bestellen (verknüpft Control 1.2.2) | +| Q-ROLE-02/03 ISB = IT-Verantwortung | `organizational` – Funktionstrennung herstellen/kompensieren (C7) | +| Q-FEAT-09 „externe IT-Dienstleister = ja" | `evidence_provide` – Selbstauskunft/TISAX-Nachweis einholen (Control 6.1.1) | +| Q-FEAT-02/03 Cloud/KI = ja, ohne Freigabeverfahren | `document_create` – Cloud-/KI-Freigabeverfahren aktivieren (VA-11) | +| Q-BL-11 „kein Wiederherstellungstest" | `technical` – Restore-Test etablieren (BL-OPS-06, Control 5.2.9) | + +> Hinweis: Die vollständige Antwort→Wirkung-Matrix wird maschinenlesbar als Regelobjekte (B2-DSL) hinterlegt; diese Tabelle ist die fachliche Spezifikation dafür. Neue `FLAG_*` bitte zuerst in `variables.schema.json` ergänzen (Single Source of Truth), dann Frage + Wirkung hier. diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C3_Vorlagen-Annotation.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C3_Vorlagen-Annotation.md new file mode 100644 index 0000000..b660fd8 --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C3_Vorlagen-Annotation.md @@ -0,0 +1,49 @@ +# C3 — Regelfähige Vorlagen-Auszeichnung (Annotationskonvention + Verify + Erweiterung) + +> **Schaltet frei:** B4 (Richtlinien – Import + Upload + Control-Mapping). **Grundlage:** `isms-vorlagenpaket-v2/` (34 Vorlagen, `mapping.json`, `variables.schema.json`, `_verify.py`). + +## 1. Ist-Zustand (Informationssicherheit) — vollständig annotiert + +Das Vorlagenpaket ist für die **Informationssicherheit** bereits regelfähig ausgezeichnet und konsistent: + +- **34 Vorlagen** – Leitlinie `L00`, Richtlinien `R01–R14`, Verfahren `VA-01 … VA-19`, plus `Technische-Sicherheits-Baseline.md`, `Nachweisregister_zentral.md`, `ISA-Mapping-Matrix.md`. +- **316 Anforderungen** in `mapping.json` (312 ISA + 4 kundenspezifisch KI), je mit stabiler ID, `type`, `level`, `policy`, `condition`-Flag, `req_anchor`/`impl_anchor`, `verfahren`. +- **`python3 _verify.py` → OK** (Render ohne offene Platzhalter für `FLAG_INCLUDE_SHOULD` an/aus, keine verwaisten Anker, keine Handlebars-Reste). **Dieser Lauf ist die Abnahmebedingung jeder Änderung.** + +Für Informationssicherheit ist C3 damit als „bestätigt/konsistent" zu betrachten; die SME-Aufgabe ist Pflege + die Erweiterung um Prototypenschutz/Datenschutz (Abschnitt 3). + +## 2. Annotationskonvention (verbindlich für alle Vorlagen) + +| Konstrukt | Bedeutung | Beispiel | +|---|---|---| +| `{{VARIABLE}}` | Variable aus `variables.schema.json` | `{{ORG_NAME}}`, `{{MFA_SCOPE}}` | +| `{{#if FLAG_X}} … {{/if}}` | Bedingter Block (Feature-Flag/Reifegrad/Schutzbedarf) | `{{#if FLAG_HIGH_PROTECTION}} … {{/if}}` | +| `[MUSS]`/`[SOLL]`/`[HOCH]`/`[SEHR HOCH]` | Sichtbare Kennzeichnung der Anforderungsstufe | `- **[SOLL]** …` | +| `<!-- REQ <id> -->` | Hidden-Anker vor einer Einzelanforderung | `<!-- REQ 4.1.2-H1 -->` | +| `<!-- IMPL <control> -->` | Hidden-Anker vor dem Umsetzungstext (Control-gebündelt) | `<!-- IMPL 4.1.2 -->` | +| `<!-- IMPL <control>-elev -->` | Umsetzungsvariante für erhöhten Schutzbedarf | `<!-- IMPL 4.1.2-elev -->` | +| `{{LINK:ZIEL}}` | Laufzeit-Link (Dokument/Nachweisregister) | `{{LINK:R08#4.1.2}}` | +| Verfahrensanker `<!-- FULFILLS <ids> | POLICY <Rxx> -->` | VA erfüllt Anforderungen | in `VA-*` | + +**Regeln für eine regelfähige Auszeichnung** + +1. Jede Einzelanforderung erhält genau einen `<!-- REQ <id> -->`-Anker, dessen ID exakt der `mapping.json`-`id` entspricht. +2. `[SOLL]` immer in `{{#if FLAG_INCLUDE_SHOULD}}`, `[HOCH]` in `{{#if FLAG_HIGH_PROTECTION}}`, `[SEHR HOCH]` in `{{#if FLAG_VERY_HIGH_PROTECTION}}`. Der `condition`-Wert in `mapping.json` und der `{{#if}}` im Dokument müssen übereinstimmen. +3. Feature-abhängige Klauseln (Cloud/KI/OT/Dev/Mobil/PKI/Extern/Kundensysteme) in den passenden `{{#if FLAG_*}}`-Block. +4. Konkrete Zahlenwerte nie hart schreiben, sondern über Baseline-Variable (`{{PW_MIN_LENGTH}}` …) referenzieren. +5. `<!-- … -->`-Anker im Dokument belassen (im Lesemodus unsichtbar); nur der PDF-/Druckexport entfernt sie. +6. Nach jeder Änderung `python3 _verify.py` → **OK**. + +## 3. Erweiterung: Prototypenschutz (P01) + Datenschutz (D01) + +Das Paket ist „VDA ISA 2027 (Information Security)". Für die Prüfziele **Prototypenschutz (8.x)** und **Datenschutz (9.x)** sind Vorlagen + `mapping.json`-Einträge neu anzulegen — nach identischer Konvention. Vorschlag: + +- **Neue Vorlage `P01_Prototypenschutz.md`** (Richtlinie Prototypenschutz) + Verfahren `VA-20_Prototypen-Zutritt-und-Transport`. Deckt 8.1.x (physische Sicherheit/Perimeter/Zonen/Zutritt/Einbruch/Besucher/Mandantentrennung), 8.2.x (Geheimhaltung/Unterauftragnehmer/Schulung/Klassifizierung/Bildaufzeichnung), 8.3.x (Transport/Lagerung). 8.4.x/8.5.x nur bei erweitertem Prüfziel. +- **Neue Vorlage `D01_Datenschutz.md`** (Richtlinie Datenschutz) — kann `R14 Compliance & Datenschutz` erweitern/aufteilen; Verfahren `VA-18 Datenschutz-und-Compliance-Pflege` ist vorhanden. Deckt 9.1.x–9.8.x. +- Je neuer Anforderung ein `mapping.json`-Eintrag im gleichen Schema (`id`,`policy`=P01/D01,`control`,`level`,`type`,`is_isa`=true,`req_anchor`,`impl_anchor`,`condition`,`requirement`,`verfahren`). Anforderungs-IDs siehe C1/C6-Dekomposition (`8.1.1-M1` …, `9.1.1-M1` …). +- Neue `FLAG_*` bei Bedarf zuerst in `variables.schema.json` (z. B. `FLAG_PROTOTYPE_PROTECTION`), damit `_verify.py` sie kennt; Prototypenschutz-Klauseln in `{{#if FLAG_PROTOTYPE_PROTECTION}}`. +- `_verify.py` um die neuen Verzeichnisse/Anker erweitern, dann → **OK**. + +## 4. Control-Zuordnung beim manuellen Upload (B4b) + +Für hochgeladene **eigene** Richtlinien (kein Template): Pflichtfeld „belegt Controls" (Multi-Select aus dem Control-Katalog). Optional je Control die abgedeckten Anforderungs-IDs. Diese Zuordnung fließt wie ein `<!-- REQ -->`-Anker in die Nachweislage (Schritt 7) — ohne Tailoring, aber mit voller Reifegrad-/Gap-Wirkung. Ein späterer Gap-Check (Dokumentinhalt ↔ Anforderungstext) ist als Option vorgesehen (offener Entscheidungspunkt). diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C4_Risikokatalog.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C4_Risikokatalog.md new file mode 100644 index 0000000..e6a1272 --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C4_Risikokatalog.md @@ -0,0 +1,169 @@ +# C4 — Standard-Risikokatalog (VDA ISA / TISAX) + +**Paket:** C4 — Kuratierter Risiko-Katalog für den Onboarding-Wizard +**Modul:** Risikomanagement +**Referenzen:** R03 Risikomanagement · VA-09 Risikomanagement-Verfahren · VDA ISA (IS 1.x–7.x, Prototypenschutz 8.x, Datenschutz 9.x) · Baseline-Parameter BL-* + +--- + +## 1. Nutzung im Wizard-Schritt „Risikomanagement" + +Dieser Katalog wird dem Kunden im Onboarding-Wizard als kuratierte Vorauswahl typischer Informationssicherheits- und TISAX-Risiken angeboten. Der Ablauf: + +1. **Auswahl** — Der Kunde markiert die für seinen Scope zutreffenden Risiken. Nicht zutreffende Risiken (z. B. Prototypenschutz ohne physische Musterteile, Entwicklung ohne eigene Softwareentwicklung) werden abgewählt oder als „nicht anwendbar" begründet. +2. **Ergänzung** — Der Kunde ergänzt eigene, organisationsspezifische Risiken. +3. **Bewertung** — Jedes ausgewählte Risiko wird nach der 5×5-Matrix bewertet (Eintrittswahrscheinlichkeit × Schadenshöhe). Die im Katalog hinterlegte **Default-Einschätzung** ist ein Startwert und vom Kunden anzupassen. +4. **Maßnahmenableitung** — Aus dem bewerteten Risiko werden Maßnahmen abgeleitet (Standardmaßnahmen sind vorbelegt). Maßnahmen erzeugen im System **Aufgaben** mit Verantwortlichen und Fristen. +5. **Restrisiko** — Nach Maßnahmenumsetzung erfolgt eine erneute Bewertung (Netto-/Restrisiko). Restrisiken oberhalb der Akzeptanzschwelle erfordern eine dokumentierte Risikoakzeptanz durch die Leitung (siehe VA-09). + +### Bewertungslogik (5×5) + +| Achse | Stufen | Kurzdefinition | +|-------|--------|----------------| +| **Eintrittswahrscheinlichkeit (E)** | 1 sehr gering · 2 gering · 3 mittel · 4 hoch · 5 sehr hoch | Erwartete Häufigkeit im Betrachtungszeitraum (i. d. R. 12 Monate) | +| **Schadenshöhe (S)** | 1 vernachlässigbar · 2 gering · 3 spürbar · 4 hoch · 5 existenzbedrohend | Auswirkung auf Vertraulichkeit/Integrität/Verfügbarkeit, Vertrag, Reputation, Recht | + +**Risikowert = E × S** (1–25). Klassifizierung gemäß VA-09: + +- **1–4 gering** (grün) — beobachten, ggf. akzeptieren +- **5–9 mittel** (gelb) — Maßnahmen empfohlen +- **10–15 hoch** (orange) — Maßnahmen verbindlich, Termin gesetzt +- **16–25 sehr hoch** (rot) — Sofortmaßnahmen, Eskalation an Leitung + +Die Default-Einschätzung je Risiko ist als **E/S** angegeben (z. B. „E3/S4"). Sie geht von einem typischen KMU-Zuliefererbetrieb ohne bereits umgesetzte Maßnahmen aus (Brutto-/Ausgangsrisiko). + +### ID-Schema + +`R-<KATEGORIE>-<lfd. Nr.>` — Kategorien: ORG (Organisation/Governance), HR (Personal), PHY (Physisch), IAM (Identitäts-/Zugriffsmanagement), CRY (Kryptografie), OPS (Betrieb/IT), NET (Netzwerk), SUP (Lieferanten/Cloud), DEV (Entwicklung), PROTO (Prototypenschutz), DSGVO (Datenschutz). + +--- + +## 2. Organisation / Governance + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-ORG-01 | Fehlende/veraltete IS-Leitlinie & Verantwortlichkeiten | Es existiert keine von der Leitung verabschiedete Informationssicherheitsleitlinie oder Rollen (ISB/CISO) sind nicht benannt, sodass Steuerung und Verbindlichkeit fehlen. | 1.1.1, 1.2.1, 1.3.1 | Richtlinien, Organisation | IS-Leitlinie nach R03 erstellen/aktualisieren, ISB benennen, jährliches Management-Review etablieren | E3/S4 — ohne Governance keine wirksame Steuerung; Schaden trifft gesamtes ISMS | +| R-ORG-02 | Kein funktionierendes Risikomanagement | Risiken werden nicht systematisch erfasst, bewertet oder behandelt; TISAX-Anforderung an Risikoprozess ist nicht erfüllt. | 1.4.1 | Prozesse, Dokumentation | Risikomanagement-Verfahren VA-09 einführen, Risiko-Register führen, Reviews terminieren | E3/S4 — Kernanforderung TISAX; Assessment-Abweichung wahrscheinlich | +| R-ORG-03 | Fehlendes Asset- und Informationsklassifizierungsschema | Werte (Informationen, Systeme) sind nicht inventarisiert oder klassifiziert, sodass Schutzbedarf und Maßnahmen nicht zielgerichtet zugeordnet werden können. | 1.3.2, 1.3.3, 5.2.x | Informationswerte, Inventar | Asset-Inventar aufbauen, Klassifizierungsschema (intern/vertraulich/streng vertraulich) einführen und kennzeichnen | E3/S3 — Grundlage vieler Controls; ohne Klassifizierung Fehlschutz | +| R-ORG-04 | Unzureichende IS-Vorgabendokumentation / veraltete Verfahren | Verfahrensanweisungen und Richtlinien sind nicht vorhanden, veraltet oder werden nicht gelebt, was zu inkonsistentem Handeln führt. | 1.2.x, 1.5.1 | Dokumentation | Dokumentenlenkung nach R03 etablieren, Review-Zyklus (jährlich), Freigabe- und Versionskontrolle | E3/S3 — Nachweisführung im Assessment gefährdet | +| R-ORG-05 | Fehlendes Vorfalls- / Incident-Management | Sicherheitsvorfälle werden nicht erkannt, gemeldet, dokumentiert oder ausgewertet, wodurch Schäden eskalieren und Lernen ausbleibt. | 1.6.1 | Prozesse | Incident-Response-Prozess einführen, Meldewege und Eskalation definieren, Vorfallregister führen | E3/S4 — verzögerte Reaktion vergrößert Schaden erheblich | +| R-ORG-06 | Fehlendes Business Continuity / Notfallmanagement | Für Ausfälle kritischer Prozesse/IT existieren keine Notfall- und Wiederanlaufpläne, sodass Betriebsunterbrechungen unkontrolliert verlaufen. | 1.6.x, 7.x | Prozesse, IT-Systeme | BCM-Konzept und Wiederanlaufpläne erstellen, Notfallübungen jährlich, Bezug zu BL-OPS-05 (Backup) | E2/S4 — selten, aber hoher Schaden bei Eintritt | + +--- + +## 3. Personal + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-HR-01 | Mangelndes Sicherheitsbewusstsein der Mitarbeitenden | Beschäftigte sind nicht regelmäßig geschult und fallen auf Phishing/Social Engineering herein oder handeln fahrlässig. | 2.1.2, 2.1.3 | Personal, Informationen | Awareness-Programm und jährliche Schulungen einführen, Phishing-Simulationen, Schulungsnachweise dokumentieren | E4/S3 — Mensch häufigster Angriffsvektor | +| R-HR-02 | Fehlende Vertraulichkeits-/Geheimhaltungsvereinbarungen | Mit Mitarbeitenden, Zeitarbeit oder Externen sind keine NDAs abgeschlossen, sodass der Schutz vertraulicher Informationen rechtlich nicht abgesichert ist. | 2.1.1 | Verträge, Personal | NDA/Verpflichtung auf Vertraulichkeit in Onboarding-Prozess verankern, Bestand nachpflegen | E3/S3 — häufige Lücke bei Externen/Zeitarbeit | +| R-HR-03 | Unsicheres On-/Offboarding (Berechtigungen bei Austritt) | Bei Eintritt, Wechsel oder Austritt werden Zugänge und Assets nicht zeitnah vergeben/entzogen, sodass verwaiste Konten und Datenmitnahme entstehen. | 2.1.x, 3.1.1 | Konten, Endgeräte | On-/Offboarding-Checkliste mit HR/IT, Fristen für Kontoentzug und Asset-Rückgabe, regelmäßiger Abgleich | E3/S3 — verwaiste Konten sind typischer Auditfund | +| R-HR-04 | Innentäter / Datenmitnahme durch Mitarbeitende | Berechtigte Personen entwenden oder missbrauchen vorsätzlich Informationen (z. B. Konstruktionsdaten) zum eigenen Vorteil oder für Wettbewerber. | 2.1.x, 5.2.x, 3.1.x | Informationen, geistiges Eigentum | Need-to-know umsetzen, Protokollierung sensibler Zugriffe, DLP-Ansätze, arbeitsrechtliche Regelungen | E2/S4 — selten, aber sehr hoher Schaden für IP | + +--- + +## 4. Physische Sicherheit + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-PHY-01 | Unberechtigter Zutritt zu Betriebs-/Sicherheitsbereichen | Fehlende Zutrittskontrolle ermöglicht Unbefugten Zugang zu Büros, Serverräumen oder Fertigung, mit Diebstahl- und Manipulationsrisiko. | 4.1.1, 4.1.2 | Gebäude, IT-Systeme | Zonenkonzept, Zutrittskontrollsystem/Schließplan, Besucherregelung mit Begleitung und Protokoll | E3/S3 — Grundschutzanforderung, oft lückenhaft | +| R-PHY-02 | Unzureichender Schutz von Server-/Technikräumen | Serverräume sind nicht ausreichend gegen Zutritt, Brand, Wasser, Strom-/Klimaausfall geschützt, was zu Ausfall oder Datenverlust führt. | 4.1.x, 7.x | IT-Infrastruktur | Technikraum absichern (Zutritt, USV, Klima, Brand-/Wasserschutz), Umgebungsüberwachung | E2/S4 — geringe Häufigkeit, hoher Ausfallschaden | +| R-PHY-03 | Diebstahl/Verlust von Datenträgern und Dokumenten | Papierunterlagen, USB-Medien oder Datenträger mit vertraulichen Informationen gehen verloren oder werden entwendet. | 4.1.x, 5.2.x | Datenträger, Dokumente | Clean-Desk-Policy, verschließbare Schränke, sichere Entsorgung (Schredder/zertifiziert), Medienverschlüsselung | E3/S3 — alltägliches Restrisiko | + +--- + +## 5. Identitäts- und Zugriffsmanagement (IAM) + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-IAM-01 | Fehlberechtigungen / überzogene Zugriffsrechte | Zugriffsrechte folgen nicht dem Need-to-know- und Least-Privilege-Prinzip; Sammelrechte und Rechteakkumulation entstehen. | 3.1.1, 3.1.2, 3.1.3 | Konten, Anwendungen, Daten | Rollen-/Rechtekonzept (RBAC), regelmäßige Rezertifizierung der Berechtigungen, Trennung von Funktionen | E4/S3 — häufigster Auditfund im IAM | +| R-IAM-02 | Schwache Authentisierung / fehlende MFA | Zugänge (insb. remote, Admin, Cloud) sind nur durch schwache Passwörter geschützt, wodurch Kontoübernahmen leicht möglich sind. | 3.1.4, 3.1.5 | Konten, Zugänge | Passwortrichtlinie (BL-IAM-*), MFA für Remote-/Admin-/Cloud-Zugänge verpflichtend, SSO | E4/S4 — Credential-Angriffe sehr häufig und wirksam | +| R-IAM-03 | Ungesicherte / geteilte privilegierte Konten | Administrative und Sammelkonten werden geteilt genutzt und nicht überwacht, sodass Handlungen nicht zurechenbar sind. | 3.1.x | Admin-Konten | Privileged-Access-Management, personalisierte Admin-Konten, Protokollierung, getrennte Admin-Arbeitsplätze | E3/S4 — Missbrauch privilegierter Rechte hochwirksam | + +--- + +## 6. Kryptografie + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-CRY-01 | Fehlende Verschlüsselung mobiler Geräte / Datenträger | Notebooks, Smartphones und Wechselmedien sind nicht verschlüsselt, sodass bei Verlust/Diebstahl Daten unmittelbar lesbar sind. | 5.1.1, 5.1.2 | Endgeräte, Datenträger | Full-Disk-Encryption (BitLocker/FileVault) verpflichtend, MDM-erzwungene Verschlüsselung, Medienrichtlinie | E3/S4 — Verlustfall führt sonst direkt zu Datenabfluss | +| R-CRY-02 | Unsichere Datenübertragung (fehlende Transportverschlüsselung) | Vertrauliche Daten werden unverschlüsselt (E-Mail, FTP, HTTP) übertragen und können abgefangen werden. | 5.1.1 | Kommunikation, Daten | TLS erzwingen, sichere Austauschwege/Portale, E-Mail-Verschlüsselung für vertrauliche Inhalte | E3/S3 — Abfangrisiko bei Zulieferaustausch | +| R-CRY-03 | Unzureichendes Schlüssel-/Zertifikatsmanagement | Kryptografische Schlüssel und Zertifikate werden nicht sicher verwaltet oder laufen unbemerkt ab, was zu Ausfällen oder Kompromittierung führt. | 5.1.x | Schlüssel, Zertifikate | Krypto-Richtlinie, zentrale Schlüssel-/Zertifikatsverwaltung, Ablaufüberwachung, sichere Aufbewahrung | E2/S3 — schleichender, aber wirkungsvoller Ausfall | + +--- + +## 7. Betrieb / IT + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-OPS-01 | Fehlendes/mangelhaftes Patch- und Schwachstellenmanagement | Betriebssysteme und Anwendungen werden nicht zeitnah aktualisiert, sodass bekannte Schwachstellen ausnutzbar bleiben. | 5.2.4, 5.2.5 | IT-Systeme, Software | Patchmanagement-Prozess mit Fristen nach Kritikalität, Schwachstellenscans, Vulnerability-Tracking | E4/S4 — meistgenutztes Einfallstor, hohe Angriffsfläche | +| R-OPS-02 | Schadsoftware / Ransomware-Befall | Malware gelangt über E-Mail, Wechselmedien oder Web ins Netz und verschlüsselt oder exfiltriert Daten. | 5.2.3 | IT-Systeme, Daten | Endpoint-Protection/EDR flächendeckend, E-Mail-/Web-Filter, Makro-Restriktionen, Awareness (R-HR-01) | E4/S5 — hohe Häufigkeit, potenziell existenzbedrohend | +| R-OPS-03 | Backup-/Wiederanlauf-Versagen | Datensicherungen fehlen, sind unvollständig, nicht getestet oder mitverschlüsselbar, sodass eine Wiederherstellung im Ernstfall scheitert. | 7.x | Daten, IT-Systeme | Backup-Konzept nach BL-OPS-05 (3-2-1, Offline-/Immutable-Kopie), regelmäßige Restore-Tests, RTO/RPO definieren | E3/S5 — im Ransomware-Fall entscheidend für Überleben | +| R-OPS-04 | Fehlende Protokollierung und Überwachung (Logging/Monitoring) | Sicherheitsrelevante Ereignisse werden nicht protokolliert oder ausgewertet, sodass Angriffe unentdeckt bleiben. | 5.2.6 | IT-Systeme, Logs | Zentrales Logging, Log-Auswertung/SIEM-Ansatz, Aufbewahrungsfristen, Alarmierung bei Auffälligkeiten | E3/S3 — verlängert Entdeckungszeit erheblich | +| R-OPS-05 | Schatten-IT / nicht genehmigte Software & Dienste | Mitarbeitende nutzen nicht freigegebene Cloud-Dienste oder Software, wodurch Daten unkontrolliert abfließen und Schwachstellen entstehen. | 5.2.x, 6.1.x | Anwendungen, Daten | Freigabeprozess für Software/Dienste, Anwendungsinventar, technische Restriktionen, Awareness | E3/S3 — verbreitet, schwer sichtbar | +| R-OPS-06 | Fehlkonfiguration / fehlendes Change-Management | Systeme werden ohne kontrollierte Änderungsprozesse betrieben, sodass Fehlkonfigurationen Sicherheitslücken und Ausfälle verursachen. | 5.2.1, 5.2.2 | IT-Systeme, Konfiguration | Härtungs-/Konfigurationsvorgaben (Baselines), Change-Management-Prozess, Test vor Produktivsetzung | E3/S3 — Fehlkonfiguration häufige Ausfall-/Angriffsursache | +| R-OPS-07 | Verlust/Diebstahl mobiler Endgeräte | Notebooks, Smartphones oder Tablets gehen unterwegs verloren oder werden gestohlen und ermöglichen Zugriff auf Daten und Systeme. | 5.2.x, 5.1.1 | Endgeräte, Daten | MDM mit Remote-Wipe, Geräteverschlüsselung (R-CRY-01), Bildschirmsperre, Verlustmeldeprozess | E3/S3 — mobiles Arbeiten erhöht Häufigkeit | +| R-OPS-08 | Fehlende sichere Entsorgung / Wiederverwendung von IT | Ausgemusterte Geräte und Datenträger werden ohne sichere Löschung entsorgt oder weitergegeben, sodass Restdaten abfließen. | 5.2.x, 4.1.x | Datenträger, Endgeräte | Prozess zur sicheren Löschung/Vernichtung, zertifizierte Entsorgung, Nachweisführung | E2/S3 — selten, aber unbemerkter Datenabfluss | + +--- + +## 8. Netzwerk + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-NET-01 | Unsichere Netzsegmentierung / flaches Netz | Fehlende Trennung zwischen Office-, Produktions-/OT- und Gastnetzen ermöglicht laterale Ausbreitung von Angriffen. | 5.2.x | Netzwerk, IT-Systeme | Netzsegmentierung (VLAN/Zonen), Firewall-Regelwerk, Trennung OT/IT und Gast-WLAN | E3/S4 — begünstigt großflächige Kompromittierung | +| R-NET-02 | Unsicherer Remote-/VPN-Zugang | Fernzugriffe sind nicht ausreichend abgesichert (kein MFA, offene Ports, veraltete VPN-Gateways) und werden angegriffen. | 5.2.x, 3.1.4 | Zugänge, Netzwerk | Gehärtetes VPN mit MFA, Zugriff nach Least-Privilege, Patching der Gateways, Zugriffprotokollierung | E3/S4 — Remote-Zugänge sind bevorzugtes Angriffsziel | +| R-NET-03 | Unzureichender Perimeter-/Firewall-Schutz | Fehlende oder falsch konfigurierte Firewalls und exponierte Dienste erlauben direkte Angriffe aus dem Internet. | 5.2.x | Netzwerk, IT-Systeme | Firewall mit restriktivem Regelwerk, regelmäßige Regel-Reviews, Minimierung exponierter Dienste, externe Scans | E3/S4 — exponierte Dienste werden automatisiert angegriffen | + +--- + +## 9. Lieferanten / Cloud + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-SUP-01 | Lieferanten/Dienstleister ohne IS-Nachweis | Externe Partner mit Zugriff auf Informationen/Systeme verfügen über kein nachgewiesenes IS-Niveau (z. B. TISAX/ISO 27001), was Risiken in die Lieferkette trägt. | 6.1.1, 6.1.2 | Verträge, Lieferanten | Lieferantenbewertung, IS-Anforderungen und Nachweise vertraglich fordern, TISAX-Label bei sensiblen Daten | E3/S4 — Kettenrisiko, TISAX-relevant für Weitergabe | +| R-SUP-02 | Unzureichende vertragliche IS-Regelungen mit Dienstleistern | Verträge enthalten keine Vorgaben zu Vertraulichkeit, Rückgabe/Löschung, Audit- und Meldepflichten. | 6.1.x | Verträge | Standard-IS-Vertragsklauseln/Anlage, Regelungen zu Löschung, Subunternehmern, Meldung von Vorfällen | E3/S3 — Nachweislücke bei Audit | +| R-SUP-03 | Abhängigkeit von Cloud-Diensten / Datenabfluss in die Cloud | Vertrauliche Daten liegen bei Cloud-Anbietern ohne ausreichende Kontrolle über Standort, Zugriff und Ausfallabsicherung. | 6.1.x, 9.x | Cloud-Dienste, Daten | Cloud-Nutzungsrichtlinie, Anbieterprüfung (Zertifikate, Standort), Verschlüsselung, AVV bei Personenbezug | E3/S4 — Kontrollverlust und Lock-in | +| R-SUP-04 | Kompromittierung über die Software-Lieferkette | Manipulierte Updates, Bibliotheken oder Fernwartungszugänge von Dienstleistern führen zu Kompromittierungen. | 6.1.x, 5.2.x | Software, Zugänge | Bezugsquellen prüfen, Signaturen verifizieren, Fernwartungszugänge kontrollieren und protokollieren | E2/S4 — selten, aber weitreichende Wirkung | + +--- + +## 10. Entwicklung + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-DEV-01 | Abfluss von Entwicklungs-/Konstruktionsdaten | Vertrauliche Entwicklungsdaten (CAD, Spezifikationen, Quellcode) gelangen unkontrolliert nach außen (Cloud, Mail, private Geräte). | 5.2.x, 8.x, 6.1.x | Entwicklungsdaten, IP | Klassifizierung und Zugriffsbeschränkung (Need-to-know), sichere Austauschwege, DLP, Repository-Absicherung | E3/S5 — Kernwert des Zulieferers, hoher IP-Schaden | +| R-DEV-02 | Unsichere Software-Entwicklung (fehlender Secure SDLC) | Sicherheitsanforderungen werden in Entwicklung und Tests nicht berücksichtigt, sodass verwundbare Produkte/Software entstehen. | 5.2.x | Quellcode, Anwendungen | Secure-Coding-Vorgaben, Code-Reviews/SAST, Sicherheitstests, Trennung Entwicklungs-/Produktivumgebung | E3/S3 — je nach Entwicklungsanteil relevant | +| R-DEV-03 | Testdaten mit Echt-/Produktivdaten | In Entwicklungs- und Testumgebungen werden ungeschützte Produktiv- oder Personendaten verwendet und exponiert. | 5.2.x, 9.x | Testdaten, Personendaten | Anonymisierung/Pseudonymisierung von Testdaten, Zugriffsbeschränkung Testumgebung, Löschkonzept | E3/S3 — verbreitete Praxis, auch datenschutzrelevant | + +--- + +## 11. Prototypenschutz + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-PROTO-01 | Unberechtigter Zutritt zu Prototypen-/Musterbereichen | Unbefugte erlangen Zugang zu Bereichen mit Prototypen, Musterteilen oder Vorserien und können diese einsehen, fotografieren oder entwenden. | 8.1.x, 8.2.x | Prototypen, Räumlichkeiten | Sicherheitszonen mit Zutrittskontrolle, Begleitpflicht, Kamera-/Fotografierverbot, Besucherregelung | E3/S4 — TISAX-Prototypenschutz Kernrisiko | +| R-PROTO-02 | Unzureichender Schutz bei Erprobung/Transport von Prototypen | Bei Fahrzeugerprobung, Foto/Film oder Transport werden Prototypen unzureichend getarnt/gesichert und Dritten zugänglich. | 8.3.x, 8.4.x | Prototypen, Fahrzeuge | Tarnung/Abdeckung, gesicherte Transporte, Regelungen für Erprobung und Foto/Film, Geheimhaltungszonen | E2/S4 — seltener, aber öffentlichkeitswirksamer Schaden | +| R-PROTO-03 | Informationsabfluss zu geschützten Produkten/Projekten | Informationen zu geheimhaltungsbedürftigen Fahrzeugprojekten (Bilder, Daten, Termine) gelangen an Unbefugte oder in soziale Medien. | 8.1.x, 8.2.x | Projektinformationen | Verschärfte Klassifizierung/Kennzeichnung, Need-to-know, Schulung Prototypenschutz, Mobilgeräte-Restriktionen | E3/S4 — Reputations- und Vertragsschaden beim OEM | + +--- + +## 12. Datenschutz + +| Risiko-ID | Titel | Beschreibung | Betroffene Controls (VDA ISA) | Asset-Typen | Standardmaßnahme(n) | Default (E/S) | +|-----------|-------|--------------|-------------------------------|-------------|---------------------|---------------| +| R-DSGVO-01 | Datenschutzverstoß / meldepflichtige Datenpanne | Personenbezogene Daten werden unrechtmäßig offengelegt, verloren oder verarbeitet, was zu Meldepflicht (Art. 33/34), Bußgeld und Reputationsschaden führt. | 9.x | Personendaten | Datenschutz-Managementprozess, Datenpannen-Meldeprozess (72 h), technische/organisatorische Maßnahmen (TOM) | E3/S4 — hohe Bußgeld- und Meldepflichtrelevanz | +| R-DSGVO-02 | Fehlende Auftragsverarbeitungsverträge (AVV) | Für Dienstleister, die personenbezogene Daten verarbeiten, fehlen AVV nach Art. 28 DSGVO, sodass Verarbeitung unrechtmäßig ist. | 9.x, 6.1.x | Verträge, Personendaten | AVV-Prozess etablieren, Bestand prüfen und nachholen, Dienstleister mit Personenbezug erfassen | E3/S3 — häufige Lücke, aufsichtsrelevant | +| R-DSGVO-03 | Fehlendes Verarbeitungsverzeichnis / keine Rechtsgrundlagen | Verarbeitungstätigkeiten sind nicht dokumentiert (Art. 30) oder ohne Rechtsgrundlage, sodass Nachweispflichten verletzt werden. | 9.x | Dokumentation, Personendaten | Verzeichnis von Verarbeitungstätigkeiten führen, Rechtsgrundlagen prüfen, Löschkonzept/Fristen definieren | E3/S3 — Rechenschaftspflicht, Auditfund | +| R-DSGVO-04 | Unzulässige Übermittlung in Drittländer | Personenbezogene Daten werden ohne geeignete Garantien in Drittländer (z. B. über Cloud-Dienste) übermittelt. | 9.x, 6.1.x | Personendaten, Cloud-Dienste | Datenflüsse prüfen, Standardvertragsklauseln/Transfer-Impact-Assessment, EU-Verarbeitung bevorzugen | E2/S4 — komplex, hohe aufsichtsrechtliche Relevanz | + +--- + +## 13. Hinweise zur Pflege des Katalogs + +- Der Katalog ist eine **Startvorlage**; jede Organisation passt Auswahl, Beschreibung, Controls-Zuordnung und Bewertung an ihren Scope an. +- Controls-Angaben referenzieren die **Struktur** der VDA ISA (Kapitel 1–9). Die genauen Unter-Control-Nummern sind bei Nutzung gegen die aktuell gültige VDA-ISA-Version zu verifizieren. +- Standardmaßnahmen verweisen, wo möglich, auf vorhandene Vorlagen/Verfahren (R03, VA-09) und Baseline-Parameter (z. B. **BL-OPS-05** Backup). Weitere BL-* sind bei Umsetzung zu ergänzen. +- Jede aus einem Risiko abgeleitete Maßnahme sollte eine **Aufgabe** mit Verantwortlichem, Termin und Statusverfolgung erzeugen (VA-09). + +_Ende Paket C4 — Standard-Risikokatalog._ diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C5_Reifegradlogik.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C5_Reifegradlogik.md new file mode 100644 index 0000000..7781d2f --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C5_Reifegradlogik.md @@ -0,0 +1,199 @@ +# Paket C5 — Reifegrad-Logik je Control (Onboarding-Wizard, Schritt 7 „Control-Assessment") + +**Zweck:** Regelbasierte, nachvollziehbare Herleitung eines **Reifegrad-Vorschlags (0–3)** je Control aus den im Wizard vorhandenen Belegen (verknüpfte Dokumente, Risiken, Assets) und deren Validierungsstatus. Der Vorschlag ist **nicht bindend** — die Bestätigung/Überschreibung durch den Bearbeiter ist Pflicht (Vier-Augen-Logik über die Rolle des ISB/Assessors). + +**Grundlage:** VDA-ISA-Reifegradmodell 0–3 +- **0 — unvollständig:** Anforderung nicht oder nur zufällig erfüllt, keine belastbaren Belege. +- **1 — durchgeführt/informell:** Ergebnis wird erreicht, aber ohne festgelegte, dokumentierte Vorgehensweise. +- **2 — gesteuert/dokumentiert:** Vorgehen ist definiert, dokumentiert (Richtlinie **und** Verfahren) und mit Nachweisen belegt. +- **3 — etabliert/integriert:** Vorgehen ist in die Organisation integriert und seine **Wirksamkeit wird über die Zeit nachgewiesen** (wiederkehrende Reviews/Protokolle/Tests). + +--- + +## 1. Belegtypen und Validierungsstatus (Datenmodell-Bezug) + +Der Wizard kennt je Control folgende verknüpfbare Belegklassen: + +| Belegklasse | Herkunft im Fachcontent | Beispiel | +|---|---|---| +| **Zuständige Richtlinie (P)** | Feld `policy` (L00, R01–R14) | Leitlinie, Richtlinie | +| **Zugehöriges Verfahren (V)** | Feld `verfahren` (VA-01 … VA-19) | Verfahrensanweisung / Prozess | +| **Operativer Nachweis (N)** | control-spezifisch (Protokoll, Report, Register, Ticket, Testnachweis) | Review-Protokoll, Auditbericht | +| **Asset-Verknüpfung (A)** | Asset-Inventar | zugeordnete Informationswerte/Systeme | +| **Risiko-Verknüpfung (R)** | Risikoregister | zugeordnete Risiken + Risk Owner | + +**Validierungsstatus je Beleg:** `fehlt` → `verknüpft (unvalidiert)` → `validiert` (durch Bearbeiter bestätigt, vorhanden, aktuell). Ein Beleg zählt für Reifegrad-Sprünge nach ≥2 nur, wenn er **`validiert`** ist. + +**Aktualitätsregel (für N):** Ein operativer Nachweis gilt als „aktuell", wenn er innerhalb des für das Control definierten Review-Zyklus liegt (Standard: ≤ 12 Monate; anlassbezogene Verfahren: letzter relevanter Vorfall/Change abgedeckt). Veraltete Nachweise zählen wie `verknüpft (unvalidiert)`. + +--- + +## 2. Allgemeine Regeltabelle „Belegkonstellation → Reifegrad-Vorschlag" (generisch, für alle Controls) + +| # | Belegkonstellation | Vorschlag | Begründung | +|---|---|---|---| +| R0 | Keine Belege verknüpft **oder** nur unvalidierte Fragmente ohne zuständige Richtlinie | **0** | Kein belastbarer Nachweis einer geregelten Vorgehensweise. | +| R1a | Zuständige Richtlinie (P) verknüpft, aber **nicht validiert** | **1** | Regelungsabsicht erkennbar, aber nicht bestätigt/gelebt (informell). | +| R1b | Richtlinie (P) validiert, **aber** ein für das Control **gefordertes Verfahren (V) fehlt** oder ist unvalidiert | **1** | Richtlinie allein steuert die operative Umsetzung noch nicht. | +| R1c | Nur operativer Nachweis (N) vorhanden, **ohne** validierte Richtlinie | **1** | Tätigkeit wird durchgeführt, aber nicht dokumentiert gesteuert. | +| R2 | Richtlinie (P) **validiert** **UND** alle geforderten Verfahren (V) **validiert** **UND** (falls einschlägig) Asset-/Risiko-Verknüpfung vorhanden | **2** | Vorgehen ist dokumentiert und gesteuert, Nachweise liegen strukturell vor. | +| R3 | Zusätzlich zu R2: mindestens **ein operativer Wirksamkeitsnachweis (N) validiert und aktuell** (Review-/Audit-/Test-/Schulungs-/Rezertifizierungsprotokoll) | **3** | Wirksamkeit wird über die Zeit belegt, Vorgehen ist integriert. | + +**Sonderfälle:** +- Controls **ohne** zugeordnetes Verfahren im Fachcontent (`verfahren` = leer): Die operative Steuerung ist in der Richtlinie selbst verankert. Für Grad 2 tritt an die Stelle von (V) eine **validierte, dokumentierte Umsetzungsregelung/Konfiguration (N-basisch)**; Grad 3 erfordert weiterhin einen **wiederkehrenden Wirksamkeitsnachweis**. +- Controls, die nur `SOLL` enthalten (z. B. 5.3.3): MUSS-Ebene ist definitionsgemäß erfüllt; Bewertung startet effektiv bei 1 und folgt ansonsten der Tabelle. +- **Nachweis widerspricht Richtlinie / offene Findings im Nachweis:** Vorschlag wird um einen Grad gedeckelt (max. 1) und ein offener Punkt erzeugt. + +--- + +## 3. Zielreifegrad-Regel + +| Assessment-Scope (Kundenkonfiguration) | Standard-Zielreifegrad | +|---|---| +| **AL 3** / normaler Schutzbedarf (MUSS + SOLL im Scope) | **3** | +| **AL 2** / reiner **MUSS-Scope** | **2** | +| Control mit HOCH/SEHR-HOCH-Anforderungen im Scope (hoher/sehr hoher Schutzbedarf) | **3** (Grad 3 wird zur Pflicht, keine Absenkung) | + +- Der Zielreifegrad wird **einmal je Assessment** aus dem Scope (AL2/AL3, Schutzbedarf-Flags `FLAG_INCLUDE_SHOULD`, `FLAG_HIGH_PROTECTION`, `FLAG_VERY_HIGH_PROTECTION`) abgeleitet und je Control angezeigt. +- In der Control-Tabelle (Abschnitt 5) ist der **Standard-Zielreifegrad = 3** ausgewiesen; er sinkt automatisch auf **2**, sobald der Kunde im Onboarding einen reinen MUSS-/AL2-Scope wählt. + +--- + +## 4. „Offener-Punkt"-Kriterium (Gap/Aufgabe entsteht, wenn …) + +Ein **offener Punkt (Gap → Aufgabe)** wird automatisch erzeugt, wenn **eine** der folgenden Bedingungen zutrifft: + +1. **Vorschlag < Zielreifegrad** (Reifegradlücke). → Aufgabe: „Belege/Umsetzung bis Zielgrad X anheben". +2. **Pflichtbeleg fehlt:** zuständige Richtlinie (P) oder ein gefordertes Verfahren (V) ist `fehlt`/unvalidiert. → Aufgabe: Dokument erstellen/verknüpfen/validieren. +3. **Operativer Nachweis fehlt oder ist veraltet**, obwohl Zielgrad 3. → Aufgabe: Review/Audit/Test durchführen und dokumentieren. +4. **Asset-/Risiko-Verknüpfung fehlt** bei Controls, die auf Inventar/Risikoregister aufsetzen (z. B. 1.3.x, 1.4.1, 5.2.8). → Aufgabe: Verknüpfung herstellen. +5. **Nachweis mit Findings/Widerspruch** (Deckelung nach Abschnitt 2). → Aufgabe: Abweichung beheben. +6. **Bearbeiter überschreibt Vorschlag nach unten** oder markiert „nicht bestätigt". → Aufgabe mit Begründungspflicht. + +Jeder offene Punkt trägt: Control-ID, fehlende Belegklasse, Ist-Grad, Zielgrad, empfohlene Maßnahme, Verantwortlichen (Default: ISB). + +--- + +## 5. Control-spezifische Tabelle — IS-Controls (alle 45) + +**Legende Richtlinien (`policy`):** L00 = Informationssicherheits-Leitlinie · R01 = ISMS-Organisation/Rollen · R02 = Umgang mit Informationswerten (Asset-Mgmt) · R03 = Risikomanagement & Wirksamkeitsprüfung · R04 = Incident-/Notfall-/Kontinuitätsmanagement · R05 = Personalsicherheit · R06 = Mobiles Arbeiten/Mobile Geräte · R07 = Physische Sicherheit/Zonenkonzept · R08 = Zugriffssteuerung (IAM) · R09 = Kryptografie/Kommunikationssicherheit · R10 = IT-Betriebssicherheit · R11 = Systementwicklung/Beschaffung · R12 = Cloud/externe IT-Dienste & KI · R13 = Lieferantenmanagement · R14 = Compliance/Recht & Datenschutz. + +**Legende Verfahren (`verfahren`, abgeleitete Bezeichnungen):** VA-01 Ereignisbehandlung · VA-02 Notfall-/Kontinuitätsmgmt · VA-03 Benutzer-/Berechtigungsverwaltung · VA-04 Change-Management · VA-05 Backup & Wiederherstellung · VA-06 Schwachstellen-/Patch-/Audit-Mgmt · VA-07 Kryptografie/sichere Übertragung · VA-08 Asset-Inventarisierung & Klassifizierung · VA-09 Risikomanagement · VA-10 Lieferantensteuerung · VA-11 Cloud-/KI-Freigabe · VA-12 Schulung & Sensibilisierung · VA-13 Protokollierung/Monitoring · VA-14 Personalprozess · VA-15 Interne Audits/Compliance-Prüfung · VA-17 Zutrittsmanagement · VA-16 Sichere Entwicklung/Beschaffung · VA-18 Rechts-/Datenschutzkataster · VA-19 Projektklassifizierung. + +Format: **Reifegrad-2-Bedingung** = Vorgehen dokumentiert & gesteuert · **Reifegrad-3-Bedingung** = zusätzlich validierter, aktueller Wirksamkeitsnachweis. + +| Control | Erwartete Belege (Richtlinie / Verfahren / operativer Nachweis) | Reifegrad-2-Bedingung | Reifegrad-3-Bedingung | Ziel | +|---|---|---|---|---| +| **1.1.1** IS-Leitlinie | L00 / — / Managementfreigabe + Veröffentlichungsnachweis (Intranet), Änderungskommunikation | L00 validiert, Freigabe u. Bereitstellung dokumentiert | Wiederkehrender Leitlinien-Review (≤12 M.) + Nachweis Änderungskommunikation | 3 | +| **1.2.1** ISMS/Geltungsbereich | R01 / — / Anwendbarkeitserklärung (SoA)/ISA-Katalog, Management-Review-Protokoll | R01 validiert, Scope + SoA dokumentiert | Regelmäßige Managementbewertung mit Wirksamkeitsaussage | 3 | +| **1.2.2** Rollen & Verantwortlichkeiten | R01 / — / Rollen-/Verantwortungsmatrix, ISB-Ernennung, Qualifikationsnachweis | R01 validiert, Rollen zugewiesen u. dokumentiert | Periodische Überprüfung der Rollenbesetzung/Qualifikation | 3 | +| **1.2.3** Projektklassifizierung | R01 / VA-19 / ausgefüllte Projektklassifizierung + Projekt-Risikobewertung | R01 + VA-19 validiert | Nachweis wiederholter Klassifizierung/Neubewertung über Projekte | 3 | +| **1.3.1** Identifizierung Informationswerte | R02 / VA-08 / aktuelles Asset-/Informationswert-Inventar (**A**) | R02 + VA-08 validiert, Inventar (A) verknüpft | Nachweis regelmäßiger Inventarpflege/-abgleich | 3 | +| **1.3.2** Klassifizierung Informationswerte | R02 / VA-08 / Klassifizierungsschema + klassifizierte Assets (**A**) | R02 + VA-08 validiert, Schema angewandt | Regelmäßige Überprüfung/Neubewertung der Klassifizierung | 3 | +| **1.3.3** Externe IT-Dienste | R02 / — / Freigabe-/Bestandsliste externer Dienste, Freigabeverfahren | R02 validiert + dokumentierte Freigabeliste u. -regelung | Regelmäßige Prüfung, dass nur freigegebene Dienste genutzt werden | 3 | +| **1.3.4** Software-Freigabe | R02 / — / Softwarefreigabeliste/Whitelist, Versions-/Patchstand | R02 validiert + dokumentierte Freigabeliste | Regelmäßige Überprüfung der Softwarefreigaben | 3 | +| **1.4.1** Risikomanagement | R03 / VA-09 / Risikoregister mit Risk Ownern (**R**), Maßnahmenplan | R03 + VA-09 validiert, Risikoregister (R) verknüpft | Regelmäßige/anlassbezogene Neubewertung + Maßnahmen-Tracking | 3 | +| **1.5.1** Compliance-/Richtlinienprüfung | R03 / VA-15 / Prüfplan + Prüfaufzeichnungen/Ergebnisse | R03 + VA-15 validiert, Prüfplan vorhanden | Durchgeführte Prüfungen dokumentiert + Korrekturmaßnahmen verfolgt | 3 | +| **1.5.2** Unabhängige Überprüfung | R03 / VA-15 / Bericht unabhängiger/kompetenter Stelle, Managementbericht | R03 + VA-15 validiert | Durchgeführte unabhängige Prüfung + Maßnahmenverfolgung nachgewiesen | 3 | +| **1.6.1** Meldung Sicherheitsereignisse | R04 / VA-01 / dokumentierte Meldewege/-kanäle, Meldeformular/Ticketsystem | R04 + VA-01 validiert, Meldewege bekannt | Nachweis genutzter Meldewege (Tickets) + ggf. Test der Meldung | 3 | +| **1.6.2** Behandlung Sicherheitsereignisse | R04 / VA-01 / Incident-Log/Tickethistorie mit Lessons Learned | R04 + VA-01 validiert | Bearbeitete Vorfälle + Lessons-Learned-Rückfluss nachgewiesen | 3 | +| **1.6.3** Krisen-/Notfallmanagement | R04 / VA-02 / Krisen-/Notfallplan, Krisenstab, Übungs-/Testprotokoll | R04 + VA-02 validiert, Plan u. Rollen dokumentiert | Durchgeführte Krisenübung/Test + Aktualisierung der Planung | 3 | +| **2.1.1** Personalprüfung (Eignung/Identität) | R05 / VA-14 / Einstellungsprozess, dokumentierte Identitätsprüfung | R05 + VA-14 validiert | Nachweis gelebter Prüfung über Einstellungen (Stichprobe) | 3 | +| **2.1.2** Verpflichtungen (NDA/Richtlinien) | R05 / VA-14 / unterzeichnete Vertraulichkeits-/Richtlinienverpflichtungen | R05 + VA-14 validiert, Verpflichtungen vorhanden | Nachweis flächendeckender, aktueller Verpflichtungen | 3 | +| **2.1.3** Schulung & Sensibilisierung | R05 / VA-12 / Schulungskonzept + Teilnahmenachweise | R05 + VA-12 validiert, Konzept genehmigt | Regelmäßig durchgeführte Schulungen + Teilnahmedokumentation | 3 | +| **2.1.4** Mobiles Arbeiten | R06 / — / kommunizierte Regelung, Sensibilisierungsnachweis | R06 validiert + dokumentierte Anforderungen | Nachweis Sensibilisierung + Überprüfung der Umsetzung | 3 | +| **3.1.1** Sicherheitszonenkonzept | R07 / VA-17 / Zonenkonzept + Umsetzungsnachweis, Zutritts-/Besucherverfahren | R07 + VA-17 validiert, Zonenkonzept umgesetzt | Regelmäßige Überprüfung von Zonen/Zutritt/Besuchermgmt | 3 | +| **3.1.4** Mobile Geräte/Datenträger | R06 / — / Regelung + Geräteregistrierung/MDM-Nachweis | R06 validiert + dokumentierte Anforderungen/Registrierung | Nachweis Umsetzung (MDM/Verschlüsselung) + Überprüfung | 3 | +| **4.1.1** Identifikationsmittel (Lebenszyklus) | R08 / VA-03 / Ausgabe-/Rückgabe-/Sperrprozess, Nachweis kontrollierte Erstellung | R08 + VA-03 validiert | Nachweis gelebter Sperr-/Rückgabeprozesse (z. B. Verlustfall) | 3 | +| **4.1.2** Benutzerauthentifizierung | R08 / — / Authentifizierungskonzept, techn. Umsetzung (Passwortpolicy/MFA) | R08 validiert + dokumentiertes Auth-Konzept | Nachweis wirksamer Umsetzung (MFA-/Policy-Report) + Review | 3 | +| **4.1.3** Verwaltung Benutzerkonten | R08 / VA-03 / Kontenverwaltungsprozess, Konten-Rezertifizierung | R08 + VA-03 validiert | Regelmäßige Konten-Überprüfung/Rezertifizierung nachgewiesen | 3 | +| **4.2.1** Verwaltung Zugriffsrechte | R08 / VA-03 / Berechtigungskonzept, Rechte-Review/Rezertifizierung | R08 + VA-03 validiert | Regelmäßige Rechte-Rezertifizierung nachgewiesen | 3 | +| **5.1.1** Kryptografie | R09 / VA-07 / Kryptokonzept, Nachweis eingesetzter Verfahren | R09 + VA-07 validiert, Konzept umgesetzt | Regelmäßige Überprüfung der Krypto-Verfahren/Stand der Technik | 3 | +| **5.1.2** Netzdienste/sichere Übertragung | R09 / VA-07 / Netzdienst-Inventar, Verschlüsselungsnachweis | R09 + VA-07 validiert, Dienste dokumentiert | Nachweis wirksamer (Transport-)Verschlüsselung + Überprüfung | 3 | +| **5.2.1** Change-Management | R10 / VA-04 / Change-Prozess, Change-Tickets/CAB-Protokolle | R10 + VA-04 validiert | Nachweis gelebter Changes inkl. IS-Bewertung + Verifikation | 3 | +| **5.2.2** Trennung Entw./Test/Prod | R10 / — / Risikobewertung + Segmentierungsnachweis | R10 validiert + dokumentierte Segmentierung | Überprüfung der Trennung/Segmentierung im Betrieb | 3 | +| **5.2.3** Schutz vor Schadsoftware | R10 / — / AV-Konzept, AV-Konsole/Status-Report | R10 validiert + dokumentierte Schutzmaßnahmen | Aktueller AV-Statusreport + regelmäßige Überprüfung | 3 | +| **5.2.4** Protokollierung/Logging | R10 / VA-13 / Logging-Konzept, Log-Review-Nachweis | R10 + VA-13 validiert | Nachweis regelmäßiger Log-Auswertung/Eskalation | 3 | +| **5.2.5** Umgang mit Schwachstellen | R10 / VA-04, VA-06 / Schwachstellen-/Patchprozess, Scan-/Patchreports | R10 + VA-04 + VA-06 validiert | Aktuelle Scan-/Patchreports + Risikobehandlung nachgewiesen | 3 | +| **5.2.6** Prüfung von IT-Systemen (Audit) | R10 / VA-06 / Prüfanforderungen, Audit-/Pentestberichte | R10 + VA-06 validiert | Durchgeführte System-/Dienstprüfungen + Maßnahmen nachgewiesen | 3 | +| **5.2.7** Netzwerkmanagement | R10 / — / Netzkonzept/Segmentierung, Umsetzungsnachweis | R10 validiert + dokumentiertes Netzkonzept | Überprüfung von Netzmgmt/Segmentierung im Betrieb | 3 | +| **5.2.8** Kontinuität IT-Dienste (BCM) | R04 / VA-02 / kritische Dienste identifiziert (**A**), Kontinuitätsplan, Testprotokoll | R04 + VA-02 validiert, kritische Dienste (A) erfasst | Durchgeführter Kontinuitäts-/Wiederherstellungstest nachgewiesen | 3 | +| **5.2.9** Backup & Wiederherstellung | R10 / VA-05 / Backup-/Restore-Konzept, Restore-Testprotokoll | R10 + VA-05 validiert, Konzepte vorhanden | Durchgeführter Restore-Test (regelmäßig) nachgewiesen | 3 | +| **5.3.1** Sichere Systementwicklung/Beschaffung | R11 / VA-16 / IS-Anforderungen, Abnahme-/Testnachweise | R11 + VA-16 validiert | Nachweis durchgeführter Abnahmetests/Security-Tests | 3 | +| **5.3.2** Sicherheit Netzdienste | R11 / VA-16 / SLA/Absicherungsverfahren, Überwachungsnachweis | R11 + VA-16 validiert | Nachweis Überwachung/Qualitätssicherung der Netzdienste | 3 | +| **5.3.3** Beendigung IT-Dienste (nur SOLL) | R11 / — / vertraglich geregelter Beendigungsprozess, Nachweis Rückgabe/Löschung | R11 validiert + dokumentierter Beendigungsprozess | Nachweis gelebter Beendigung (Datenrückgabe/-löschung) | 3 | +| **5.3.4** Mandantentrennung (Cloud) | R12 / VA-11 / Trennungskonzept des Anbieters, Nachweis | R12 + VA-11 validiert | Regelmäßige Überprüfung/Anpassung des Trennungskonzepts | 3 | +| **5.3.4-KI** KI-/GenAI-Nutzung | R12 / VA-11 / KI-Nutzungsregelung + Freigabeliste, vertragl. Trainings-Ausschluss | R12 + VA-11 validiert, Freigabeliste + Datenklassen | Human-in-the-Loop-/Dokumentationsnachweis + Überprüfung | 3 | +| **6.1.1** Lieferantenmanagement | R13 / VA-10 / Lieferantenbewertung, Verträge + Nachweise/Zertifikate | R13 + VA-10 validiert, Bewertung + Verträge | Regelmäßige Überprüfung Nachweise/Vertragserfüllung (Monitoring) | 3 | +| **6.1.2** Vertraulichkeitsvereinbarungen | R13 / VA-10 / NDA-Vorlagen + abgeschlossene NDAs, Gültigkeitsüberwachung | R13 + VA-10 validiert, Vorlagen + NDAs | Regelmäßige Überprüfung/Verlängerung + gelebte NDA-Nutzung | 3 | +| **6.1.3** Geteilte Verantwortlichkeiten (Shared Resp.) | R13 / VA-10 / Verantwortungsmatrix, Nachweis Erfüllung durch Dienstleister | R13 + VA-10 validiert, Matrix dokumentiert | Nachweis, dass Dienstleister Verantwortung erfüllen (Prüfung) | 3 | +| **7.1.1** Rechtliche/vertragliche Vorgaben | R14 / VA-18 / Rechts-/Compliance-Kataster, Aktualisierungsnachweis | R14 + VA-18 validiert, Kataster vorhanden | Regelmäßige Aktualisierung des Katasters + Umsetzungsnachweis | 3 | +| **7.1.2** Datenschutz-relevante IS-Anforderungen | R14 / VA-18 / dokumentierte DS-Anforderungen, Umsetzungsnachweis im ISMS | R14 + VA-18 validiert, Anforderungen bestimmt | Nachweis Umsetzung/Überprüfung im ISMS-Kontext | 3 (MUSS-only¹) | + +¹ 7.1.2 enthält nur MUSS-Anforderungen: In reinem AL2-/MUSS-Scope Zielreifegrad **2**; ansonsten 3. + +--- + +## 6. Proto (8.x) und Datenschutz (9.x) — kompakte Gruppenlogik + +Für Prototypenschutz und Datenschutz sind im Fachcontent **keine Verfahren (VA)** hinterlegt; die Anforderungen sind überwiegend **MUSS** und stark auftraggeber-/rechtsgetrieben. Die Reifegradlogik wird daher vereinfacht: Für Grad 2 tritt an die Stelle des Verfahrens die **dokumentierte, umgesetzte Regelung** (Konzept/Prozess/Vereinbarung); Grad 3 erfordert einen **wiederkehrenden Wirksamkeits-/Umsetzungsnachweis**. + +**Generische Regel Proto/DS:** +- **0** — keine Regelung/kein Konzept belegt. +- **1** — Konzept/Vereinbarung vorhanden, aber unvalidiert oder nur informell umgesetzt. +- **2** — Konzept/Prozess/Vereinbarung **validiert und umgesetzt** (physische Maßnahme, Vertrag, dokumentierter Prozess). +- **3** — zusätzlich **validierter, aktueller Nachweis der gelebten Umsetzung** (Auditbericht, Alarmverfolgung, Schulungsnachweis, Besucherprotokoll, DSFA-Register, VVT-Pflege, Auftragskontrollen). + +**Zielreifegrad Proto/DS:** überwiegend **2** (reine MUSS-Anforderungen); für Gruppen mit SOLL/HOCH-Anteil bzw. hohem Schutzbedarf **3**. + +### 6.1 Prototypenschutz (8.x) + +| Gruppe | Controls | Erwartete Belege (Richtlinie/Regelung / operativer Nachweis) | Grad-2-Bedingung | Grad-3-Bedingung | Ziel | +|---|---|---|---|---|---| +| **8.1 Physische Sicherheit** | 8.1.1–8.1.8 | Sicherheitskonzept Prototypenschutz (Außenhaut, Zutritt, Einblickschutz, EMA/Alarmverfolgung, Besuchermgmt, Mandantentrennung) / Umsetzungs- u. Alarmverfolgungsnachweise, Besucherprotokolle | Sicherheitskonzept validiert + Schutzmaßnahmen umgesetzt | Wiederkehrende Überprüfung der phys. Maßnahmen + Alarmverfolgung/Besuchermgmt nachgewiesen | 2–3² | +| **8.2 Organisation/Vertrag/Personal** | 8.2.1–8.2.7 | NDAs (Firma + Personen), Zutrittsvergabeprozess, Schulungskonzept Prototypen, Bild-/Geräteregelungen / unterzeichnete NDAs, Schulungsnachweise, Zutrittslogs | Vereinbarungen/Prozesse validiert u. dokumentiert | Nachweis gelebter Umsetzung (Schulungen, Zutritts-Reviews, Nachweise Unterauftragnehmer) | 2 | +| **8.3 Transport/Lagerung** | 8.3.1–8.3.2 | Prozess Einholung Auftraggebervorgaben, freigegebene Logistiker / Nachweis Einhaltung/Meldeprozess | Prozesse validiert u. implementiert | Nachweis gelebter Transport-/Lagerkontrollen u. Ereignismeldung | 2 | +| **8.4 Tarnung/Erprobung** | 8.4.1–8.4.3 | Tarnungs-/Erprobungsregeln, Meldeprozess Beschädigungen / Nachweis Bekanntgabe u. Einhaltung | Regeln/Prozesse validiert u. bekannt | Nachweis gelebter Einhaltung + Meldungen bei Vorfällen | 2 | +| **8.5 Ausstellungen/Foto-Film** | 8.5.1–8.5.2 | Prozess Auftraggebervorgaben, freigegebene Sicherheitskonzepte / Freigabenachweise, Verhaltensregeln | Prozesse + freigegebene Konzepte validiert | Nachweis gelebter Umsetzung je Veranstaltung/Shooting | 2 | + +² 8.1.4/8.1.5/8.1.8 mit HOCH-Anteil (schutzbedürftige Fahrzeuge): Zielreifegrad 3. + +### 6.2 Datenschutz (9.x) + +| Gruppe | Controls | Erwartete Belege (Richtlinie/Regelung / operativer Nachweis) | Grad-2-Bedingung | Grad-3-Bedingung | Ziel | +|---|---|---|---|---|---| +| **9.1 Richtlinie DS** | 9.1.1 | DS-Richtlinie (freigegeben) / Aktualisierungs-/Freigabenachweis | DS-Richtlinie validiert u. freigegeben | Regelmäßige Aktualisierung/Review nachgewiesen | 2 | +| **9.2 Verantwortlichkeiten DS** | 9.2.1 | DSB-Bestellung/DS-Funktion, Kontaktveröffentlichung, Ressourcen / Kontroll- u. Berichtsdokumentation | Bestellung/Funktion + Eingliederung validiert | Nachweis ausgeübter Kontrollpflichten + Managementbericht | 2 | +| **9.3 Verarbeitungsverzeichnis** | 9.3.1 | VVT (Art. 30), Prozessbeschreibung/Zuständigkeiten / VVT-Pflegenachweis | VVT + Prozess validiert | Regelmäßige VVT-Pflege/Aktualität nachgewiesen | 2 | +| **9.4 DSFA** | 9.4.1 | Kriterien/Liste DSFA-pflichtiger Verarbeitungen, DSFA-Verfahren / durchgeführte DSFA | DSFA-Verfahren + Zuständigkeiten validiert | Durchgeführte DSFA + Maßnahmen nachgewiesen | 2 | +| **9.5 Datenübermittlung/AV** | 9.5.1–9.5.3 | AV-Verträge (Art. 28), Transferinstrumente, Drittland-Garantien / Nachweis Verträge/Prüfungen | Prozesse + Verträge validiert | Nachweis Überprüfung Einhaltung + Drittland-Erfassung (TIA) | 2 | +| **9.6 Betroffenenrechte/Vorfälle** | 9.6.1–9.6.2 | Verfahren Betroffenenanfragen, DS-Vorfall-/Notfallplan, Schulung / Bearbeitungs-/Meldenachweise | Verfahren validiert u. dokumentiert | Nachweis fristgerechter Bearbeitung + Meldeprozesse gelebt | 2 | +| **9.7 Personal DS** | 9.7.1–9.7.2 | Vertraulichkeitsverpflichtungen, DS-Schulungskonzept / Verpflichtungs- u. Schulungsnachweise | Verpflichtung + Schulungskonzept validiert | Regelmäßige DS-Schulungen + Verpflichtungen nachgewiesen | 2 | +| **9.8 Weisungen AV** | 9.8.1 | Verfahren Weisungsumgang, Datentrennung nach Auftrag / Dokumentation Weisungen | Verfahren + Maßnahmen validiert | Nachweis dokumentierter/umgesetzter Weisungen + Trennung | 2 | + +--- + +## 7. Umsetzungshinweis Wizard (Pseudologik) + +``` +ziel = ableiteZiel(scope) // AL3 -> 3, AL2/MUSS -> 2, HOCH/V-HOCH -> 3 +p = statusRichtlinie(control.policy) +v = min(statusAllerVerfahren(control.verfahren)) // leer -> „n/a" (durch N-basisch ersetzt) +n = statusOperativerNachweis(control) // inkl. Aktualitätsprüfung +a = statusAssetVerknuepfung(control) // nur falls einschlägig +r = statusRisikoVerknuepfung(control) // nur falls einschlägig + +if p != validiert: vorschlag = (p == verknuepft) ? 1 : 0 +elif verfahrenGefordert && v != validiert: vorschlag = 1 +elif einschlaegigA && a != verknuepft: vorschlag = 1 +else: vorschlag = 2 +if vorschlag == 2 && n == validiert_aktuell: vorschlag = 3 +if nachweisMitFindings: vorschlag = min(vorschlag, 1) + +if vorschlag < ziel || pflichtbelegFehlt || (ziel==3 && n!=validiert_aktuell): + erzeugeOffenenPunkt(control, ist=vorschlag, ziel, fehlendeBelege) + +// Pflicht: Bearbeiter bestätigt oder überschreibt vorschlag (mit Begründung) +``` + +**Kernprinzip:** Der Wizard schlägt vor, der Bearbeiter entscheidet. Jeder Vorschlag ist über die verknüpften, validierten Belege vollständig nachvollziehbar; jede Lücke zwischen Vorschlag und Zielreifegrad wird automatisch in einen offenen Punkt (Aufgabe) überführt. diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C6_Umsetzungshinweise.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C6_Umsetzungshinweise.md new file mode 100644 index 0000000..4100ccb --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C6_Umsetzungshinweise.md @@ -0,0 +1,3778 @@ +# C6 — Umsetzungshinweise je Teilanforderung + +> **Schaltet frei:** B5 (Umsetzungshinweise-Panel) + A7 (Control-Assessment). **Grundlage:** `mapping.json` (Anforderungs-IDs) + Proto/DS-Dekomposition. +> Je Anforderung: organisatorische & technische Umsetzungsoption, typische Nachweise, Vorlagen-Verweis, Ressourcenindikation, AL-Filter. Ressourcen-Hinweise mit Beschaffungs-/Umsetzungsbedarf führen im Wizard zu einer Aufgabe. + + +--- + +# Kapitel 1 — Governance & Organisation + +# C6 — Umsetzungshinweise Kapitel 1 (Informationssicherheitspolitik & Organisation) + +## Control 1.1.1 — Inwieweit werden Informationssicherheitsrichtlinien erstellt und kommuniziert? + +### 1.1.1-M1 — [MUSS] +**Anforderung:** Anforderungen der Informationssicherheit sind bestimmt, dokumentiert und an den Organisationszielen ausgerichtet. +- **Organisatorisch:** Sicherheitsanforderungen aus Geschäftszielen, Kunden-/Vertrags- und Gesetzeslage ableiten und in der Leitlinie verankern; Ableitung dokumentieren und von der Leitung bestätigen lassen. +- **Technisch:** Leitliniendokument versioniert im Dokumentenmanagement/DMS ablegen; Freigabe- und Änderungshistorie technisch nachvollziehbar führen. +- **Typische Nachweise:** genehmigte Leitlinie mit Zielbezug; Übersicht abgeleiteter Anforderungen; Freigabevermerk der Leitung. +- **Vorlage:** L00 +- **Ressourcen:** ISB/CISO; ca. 1–2 PT für Erstellung/Abstimmung; kein Toolbudget (vorhandenes DMS). +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-M2 — [MUSS] +**Anforderung:** Eine durch die Leitung genehmigte Leitlinie existiert. +- **Organisatorisch:** Formalen Genehmigungsakt durch die oberste Leitung durchführen (Managementbeschluss, Unterschrift); Genehmigung datieren. +- **Technisch:** Signierte/freigegebene Version zentral und unveränderbar (read-only) bereitstellen. +- **Typische Nachweise:** unterschriebene/freigegebene Leitlinie; Protokoll- oder Beschlussvermerk der Leitung. +- **Vorlage:** L00 +- **Ressourcen:** Leitung + ISB; gering (Termin/Freigabe). +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-M3 — [MUSS] +**Anforderung:** Die Leitlinie benennt Ziele und Bedeutung der Informationssicherheit. +- **Organisatorisch:** Abschnitt „Ziele und Stellenwert der Informationssicherheit" in die Leitlinie aufnehmen; Bezug zu Schutzzielen (C/I/A) herstellen. +- **Technisch:** Keine spezifische technische Maßnahme; Inhalt im Leitliniendokument. +- **Typische Nachweise:** Leitlinie mit Ziel- und Bedeutungskapitel. +- **Vorlage:** L00 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-M4 — [MUSS] +**Anforderung:** Leitlinien werden den Beschäftigten in geeigneter Form bereitgestellt (z. B. Intranet). +- **Organisatorisch:** Verbindlichen Veröffentlichungsweg festlegen; Bereitstellung in Onboarding-Prozess aufnehmen. +- **Technisch:** Veröffentlichung im Intranet/Mitarbeiterportal mit Lesebestätigung; Zugriff für alle Beschäftigten sicherstellen. +- **Typische Nachweise:** Intranet-Link/Screenshot; Verteil- oder Lesebestätigungen. +- **Vorlage:** L00 +- **Ressourcen:** IT/Kommunikation; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-M5 — [MUSS] +**Anforderung:** Beschäftigte und externe Geschäftspartner werden über relevante Änderungen informiert. +- **Organisatorisch:** Kommunikationsprozess für Richtlinienänderungen definieren (Zielgruppen, Kanäle, Auslöser); externe Partner über definierte Ansprechstellen einbinden. +- **Technisch:** Automatisierte Change-Benachrichtigung (Intranet-News, Verteiler) beim Publizieren neuer Versionen. +- **Typische Nachweise:** Änderungsmitteilungen; Verteilernachweise; Kommunikationsprotokoll. +- **Vorlage:** L00 +- **Ressourcen:** ISB/Kommunikation; gering, laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-S1 — [SOLL] +**Anforderung:** Anforderungen basieren auf der Organisationsstrategie; Gesetze und Verträge werden berücksichtigt. +- **Organisatorisch:** Strategie-, Rechts- und Vertragsanforderungen systematisch erheben (Legal/Compliance einbeziehen) und Bezug in der Leitlinie herstellen. +- **Technisch:** Verweis-/Anforderungsregister (Legal-Register) pflegen und mit der Leitlinie verknüpfen. +- **Typische Nachweise:** Anforderungs-/Rechtsregister; Leitlinie mit Strategie- und Rechtsbezug. +- **Vorlage:** L00 +- **Ressourcen:** ISB + Legal; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-S2 — [SOLL] +**Anforderung:** Die Leitlinie benennt Konsequenzen bei Nichteinhaltung. +- **Organisatorisch:** Sanktions-/Konsequenzenklausel abstimmen (HR, Betriebsrat) und in die Leitlinie aufnehmen. +- **Technisch:** Keine; Inhalt im Dokument. +- **Typische Nachweise:** Leitlinienabschnitt zu Konsequenzen; Betriebsrats-/HR-Abstimmung. +- **Vorlage:** L00 +- **Ressourcen:** ISB + HR; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-S3 — [SOLL] +**Anforderung:** Weitere relevante Sicherheitsrichtlinien sind etabliert. +- **Organisatorisch:** Richtlinienlandkarte aufbauen; themenspezifische Richtlinien (Zugriff, Kryptografie, mobiles Arbeiten etc.) aus dem Vorlagensatz ableiten und freigeben. +- **Technisch:** Richtliniensammlung strukturiert im DMS mit Gültigkeits-/Reviewständen. +- **Typische Nachweise:** Richtlinienübersicht; freigegebene Einzelrichtlinien. +- **Vorlage:** L00; R01–R14 +- **Ressourcen:** ISB; mehrere PT je nach Umfang. +- **AL-Filter:** AL2 + AL3 + +### 1.1.1-S4 — [SOLL] +**Anforderung:** Regelmäßige Überprüfung und ggf. Überarbeitung der Richtlinien ist etabliert. +- **Organisatorisch:** Review-Zyklus (z. B. jährlich) und anlassbezogene Prüfung festlegen; Verantwortliche und Termine definieren. +- **Technisch:** Wiedervorlage-/Review-Erinnerungen im DMS oder GRC-Tool setzen. +- **Typische Nachweise:** Review-Plan; Änderungshistorie mit Prüfdatum. +- **Vorlage:** L00; VA-15 +- **Ressourcen:** ISB; gering, laufend. +- **AL-Filter:** AL2 + AL3 + +## Control 1.2.1 — Inwieweit wird Informationssicherheit in der Organisation gemanagt (ISMS)? + +### 1.2.1-M1 — [MUSS] +**Anforderung:** Der Geltungsbereich des ISMS ist definiert. +- **Organisatorisch:** Scope nach Standorten, Organisationseinheiten, Prozessen und Dienstleistungen abgrenzen und begründen; Schnittstellen/Ausschlüsse dokumentieren. +- **Technisch:** Scope-Dokument im ISMS/GRC-Tool hinterlegen und mit Asset-/Standortlisten verknüpfen. +- **Typische Nachweise:** Scope-Dokument; Standort-/Bereichsübersicht. +- **Vorlage:** R01 +- **Ressourcen:** ISB; ca. 1–2 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.2.1-M2 — [MUSS] +**Anforderung:** Die Anforderungen der Organisation an das ISMS sind bestimmt. +- **Organisatorisch:** Interessierte Parteien und deren Anforderungen (Kunden, Regulatorik, intern) erheben und dokumentieren. +- **Technisch:** Anforderungsregister im GRC-Tool führen. +- **Typische Nachweise:** Kontext-/Stakeholder-Analyse; Anforderungsliste. +- **Vorlage:** R01 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.2.1-M3 — [MUSS] +**Anforderung:** Die Organisationsleitung hat das ISMS beauftragt und genehmigt. +- **Organisatorisch:** Formalen Auftrag/Mandat der Leitung für das ISMS und den ISB erteilen und dokumentieren. +- **Technisch:** Keine; Beschlussdokument. +- **Typische Nachweise:** ISMS-Auftrag/Mandat; Leitungsbeschluss. +- **Vorlage:** R01 +- **Ressourcen:** Leitung + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.2.1-M4 — [MUSS] +**Anforderung:** Das ISMS stellt der Leitung Mittel zur Überwachung und Steuerung bereit (z. B. Managementbewertung). +- **Organisatorisch:** Managementbewertung (Management-Review) mit Turnus, Input (Kennzahlen, Audits, Vorfälle, Risiken) und Output (Maßnahmen) etablieren. +- **Technisch:** ISMS-Kennzahlen/Dashboard im GRC-Tool bereitstellen. +- **Typische Nachweise:** Management-Review-Protokoll; ISMS-Kennzahlenbericht. +- **Vorlage:** R01; VA-15 +- **Ressourcen:** ISB + Leitung; gering, periodisch. +- **AL-Filter:** AL2 + AL3 + +### 1.2.1-M5 — [MUSS] +**Anforderung:** Die anwendbaren Controls sind bestimmt (z. B. Anwendbarkeitserklärung/ausgefüllter ISA-Katalog). +- **Organisatorisch:** Anwendbarkeit je Control festlegen und begründen (SoA/ISA); Verantwortliche zuordnen. +- **Technisch:** SoA/ISA-Katalog im GRC-Tool pflegen und mit Maßnahmen verknüpfen. +- **Typische Nachweise:** Statement of Applicability / ausgefüllter ISA-Katalog. +- **Vorlage:** R01 +- **Ressourcen:** ISB; ca. 2–3 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.2.1-M6 — [MUSS] +**Anforderung:** Die Wirksamkeit des ISMS wird regelmäßig durch die Leitung überprüft. +- **Organisatorisch:** Wirksamkeitsprüfung als festen Bestandteil des Management-Reviews mit Bewertungskriterien verankern. +- **Technisch:** Trend-/Kennzahlenauswertung (Vorfälle, Audits, Maßnahmenumsetzung) automatisiert bereitstellen. +- **Typische Nachweise:** Management-Review mit Wirksamkeitsbewertung; abgeleitete Verbesserungsmaßnahmen. +- **Vorlage:** R01; VA-15 +- **Ressourcen:** ISB + Leitung; gering, periodisch. +- **AL-Filter:** AL2 + AL3 + +## Control 1.2.2 — Inwieweit werden Verantwortlichkeiten für Informationssicherheit organisiert? + +### 1.2.2-M1 — [MUSS] +**Anforderung:** Verantwortlichkeiten für Informationssicherheit sind definiert, dokumentiert und zugewiesen. +- **Organisatorisch:** Rollen (ISB, Risk Owner, Asset Owner) und Verantwortlichkeiten festlegen und namentlich zuweisen; RACI erstellen. +- **Technisch:** Rollen-/Verantwortlichkeitsmatrix im DMS/GRC-Tool pflegen. +- **Typische Nachweise:** Rollenbeschreibungen; RACI-Matrix; Bestellungsschreiben ISB. +- **Vorlage:** R01 +- **Ressourcen:** ISB + HR; ca. 1–2 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.2.2-M2 — [MUSS] +**Anforderung:** Die verantwortlichen Beschäftigten sind definiert, qualifiziert und befähigt. +- **Organisatorisch:** Qualifikationsanforderungen je Rolle definieren; Schulungen/Zertifizierungen sicherstellen. +- **Technisch:** Qualifikations-/Schulungsnachweise im Schulungssystem dokumentieren. +- **Typische Nachweise:** Qualifikations-/Zertifikatsnachweise; Schulungsdokumentation. +- **Vorlage:** R01; VA-12 +- **Ressourcen:** HR + ISB; Schulungsbudget je Rolle. +- **AL-Filter:** AL2 + AL3 + +### 1.2.2-M3 — [MUSS] +**Anforderung:** Die erforderlichen Ressourcen stehen zur Verfügung. +- **Organisatorisch:** Personal- und Budgetbedarf des ISMS ermitteln und durch die Leitung bereitstellen lassen; im Management-Review nachhalten. +- **Technisch:** Keine; Ressourcenplanung. +- **Typische Nachweise:** Budget-/Ressourcenfreigabe; Stellen-/Kapazitätsplan. +- **Vorlage:** R01 +- **Ressourcen:** Leitung; Budget-/Personalzuweisung erforderlich. +- **AL-Filter:** AL2 + AL3 + +### 1.2.2-M4 — [MUSS] +**Anforderung:** Ansprechpartner sind innerhalb der Organisation und bei relevanten Geschäftspartnern bekannt. +- **Organisatorisch:** Ansprechpartner der Informationssicherheit intern und gegenüber Partnern kommunizieren; Aktualisierung sicherstellen. +- **Technisch:** Kontaktverzeichnis im Intranet/Portal bereitstellen. +- **Typische Nachweise:** Intranet-Kontaktseite; Kommunikation an Partner. +- **Vorlage:** R01 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.2.2-S1 — [SOLL] +**Anforderung:** Eine angemessene Informationssicherheitsstruktur ist definiert und dokumentiert. +- **Organisatorisch:** Aufbau-/Ablauforganisation der Informationssicherheit (Gremien, Berichtswege, Eskalation) beschreiben. +- **Technisch:** Organigramm/Strukturdokument im DMS. +- **Typische Nachweise:** IS-Organigramm; Gremien-/Berichtsstruktur. +- **Vorlage:** R01 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.2.2-S2 — [SOLL] +**Anforderung:** Sicherheitsrelevante Rollen außerhalb des ISMS werden berücksichtigt. +- **Organisatorisch:** Schnittstellenrollen (Datenschutz, Werkschutz, IT-Betrieb, Notfallmanagement) identifizieren und in die IS-Struktur einbinden. +- **Technisch:** Erweiterte Rollenmatrix mit Schnittstellen dokumentieren. +- **Typische Nachweise:** Rollenübersicht inkl. Schnittstellenrollen. +- **Vorlage:** R01 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.2.2-H1 — [HOCH] +**Anforderung:** Angemessene organisatorische Trennung von Verantwortlichkeiten (Funktionstrennung) zur Vermeidung von Interessenkonflikten. (C, I, A) +- **Organisatorisch:** Funktionstrennung (SoD) definieren; kritische Kombinationen identifizieren und trennen; kompensierende Kontrollen bei Kleinstteams festlegen. +- **Technisch:** SoD-Regeln in Berechtigungskonzepten und IAM-Rollen abbilden und prüfen. +- **Typische Nachweise:** SoD-Matrix; Berechtigungskonzept mit Trennungsregeln; Ausnahmedoku. +- **Vorlage:** R01; VA-03 +- **Ressourcen:** ISB + IT; ca. 1–2 PT; ggf. IAM-Konfiguration. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 1.2.3 — Inwieweit werden Informationssicherheitsanforderungen in Projekten berücksichtigt? + +### 1.2.3-M1 — [MUSS] +**Anforderung:** Projekte werden unter Berücksichtigung der Informationssicherheitsanforderungen klassifiziert. +- **Organisatorisch:** IS-Klassifizierung als verpflichtenden Schritt im Projekt-Gate/-Freigabeprozess verankern. +- **Technisch:** Klassifizierungsfeld/Checkliste im Projekt-/PM-Tool hinterlegen. +- **Typische Nachweise:** klassifizierte Projektliste; Projektfreigaben mit IS-Einstufung. +- **Vorlage:** R01; VA-19 +- **Ressourcen:** PMO + ISB; gering, laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.2.3-S1 — [SOLL] +**Anforderung:** Verfahren und Kriterien für die Projektklassifizierung sind dokumentiert. +- **Organisatorisch:** Klassifizierungskriterien (Datenschutzbedarf, Kundenbezug, Kritikalität) und Verfahren beschreiben und freigeben. +- **Technisch:** Kriterienkatalog im PM-Tool/DMS verfügbar machen. +- **Typische Nachweise:** dokumentiertes Klassifizierungsverfahren; Kriterienkatalog. +- **Vorlage:** R01; VA-19 +- **Ressourcen:** ISB + PMO; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.2.3-S2 — [SOLL] +**Anforderung:** In früher Projektphase erfolgt eine Risikobewertung nach definiertem Verfahren; Wiederholung bei Änderungen. +- **Organisatorisch:** Risikobewertung als Pflicht-Deliverable früher Projektphasen und bei wesentlichen Änderungen festlegen. +- **Technisch:** Risikobewertungsvorlage mit Projekt-Workflow verknüpfen. +- **Typische Nachweise:** Projekt-Risikobewertungen; Änderungs-Trigger-Doku. +- **Vorlage:** R01; VA-19; VA-09 +- **Ressourcen:** Projektleitung + ISB; je Projekt. +- **AL-Filter:** AL2 + AL3 + +### 1.2.3-S3 — [SOLL] +**Anforderung:** Für identifizierte Risiken werden Maßnahmen abgeleitet und im Projekt berücksichtigt. +- **Organisatorisch:** Maßnahmen aus der Risikobewertung in Projektplan/-backlog überführen und nachverfolgen. +- **Technisch:** Maßnahmen als Tasks im PM-Tool mit Verantwortlichen/Terminen führen. +- **Typische Nachweise:** Maßnahmenliste je Projekt; Statusnachverfolgung. +- **Vorlage:** R01; VA-19 +- **Ressourcen:** Projektteam; je Projekt. +- **AL-Filter:** AL2 + AL3 + +### 1.2.3-H1 — [HOCH] +**Anforderung:** Abgeleitete Maßnahmen werden im Projektverlauf regelmäßig überprüft und bei geänderten Bewertungskriterien neu bewertet. (C, I, A) +- **Organisatorisch:** Periodische Reviews der Projektmaßnahmen in Projektsteuerung/Gates verankern; Trigger für Neubewertung definieren. +- **Technisch:** Review-Termine/Reminder und Statusfelder im PM-Tool automatisieren. +- **Typische Nachweise:** Review-Protokolle; aktualisierte Risiko-/Maßnahmenstände. +- **Vorlage:** R01; VA-19; VA-09 +- **Ressourcen:** Projektleitung + ISB; laufend. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 1.3.1 — Inwieweit sind Informationswerte identifiziert und erfasst? + +### 1.3.1-M1 — [MUSS] +**Anforderung:** Informationswerte und weitere sicherheitsrelevante Assets sind identifiziert und erfasst. +- **Organisatorisch:** Erhebungsverfahren und Verantwortliche (Asset Owner) festlegen; Informationswerte je Bereich erheben. +- **Technisch:** Asset-Inventar/CMDB aufbauen und pflegen; Eindeutige IDs vergeben. +- **Typische Nachweise:** Asset-/Informationswert-Inventar; Owner-Zuordnung. +- **Vorlage:** R02; VA-08 +- **Ressourcen:** ISB + Fachbereiche; ggf. Inventar-/CMDB-Tool (Beschaffung möglich). +- **AL-Filter:** AL2 + AL3 + +### 1.3.1-M2 — [MUSS] +**Anforderung:** Die unterstützenden Assets, die Informationswerte verarbeiten, sind identifiziert und erfasst. +- **Organisatorisch:** Abhängigkeiten zwischen Informationswerten und unterstützenden Assets (Systeme, Anwendungen, Standorte, Dienstleister) erheben. +- **Technisch:** Verknüpfung Informationswert ↔ unterstützendes Asset in der CMDB abbilden. +- **Typische Nachweise:** Inventar unterstützender Assets; Abhängigkeits-/Mapping-Übersicht. +- **Vorlage:** R02; VA-08 +- **Ressourcen:** IT + Fachbereiche; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.3.1-S1 — [SOLL] +**Anforderung:** Ein Katalog relevanter Informationswerte existiert; einschlägige Aspekte werden berücksichtigt. +- **Organisatorisch:** Strukturierten Katalog mit Attributen (Owner, Klassifizierung, Speicherort, Aufbewahrung) etablieren und pflegen. +- **Technisch:** Katalog in Inventar-Tool mit Pflichtfeldern und Aktualisierungsroutine. +- **Typische Nachweise:** Informationswert-Katalog mit Attributen. +- **Vorlage:** R02; VA-08 +- **Ressourcen:** ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +## Control 1.3.2 — Inwieweit werden Informationswerte klassifiziert und geschützt? + +### 1.3.2-M1 — [MUSS] +**Anforderung:** Ein konsistentes Schema zur Klassifizierung hinsichtlich Vertraulichkeit ist vorhanden. +- **Organisatorisch:** Vertraulichkeitsstufen (z. B. öffentlich/intern/vertraulich/streng vertraulich) mit Kriterien definieren und freigeben. +- **Technisch:** Klassifizierungsschema in Vorlagen/Labels (z. B. Klassifizierungstool) verankern. +- **Typische Nachweise:** freigegebenes Klassifizierungsschema mit Stufen/Kriterien. +- **Vorlage:** R02; VA-08 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.3.2-M2 — [MUSS] +**Anforderung:** Informationswerte werden nach definierten Kriterien bewertet und dem Schema zugeordnet. +- **Organisatorisch:** Asset Owner klassifizieren ihre Informationswerte; Vollständigkeit prüfen. +- **Technisch:** Klassifizierungsattribut im Inventar/CMDB pflegen; ggf. Labeling in Dokumenten. +- **Typische Nachweise:** klassifiziertes Inventar; Stichprobe klassifizierter Werte. +- **Vorlage:** R02; VA-08 +- **Ressourcen:** Fachbereiche + ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.3.2-M3 — [MUSS] +**Anforderung:** Vorgaben zur Handhabung unterstützender Assets abhängig von der Klassifizierung sind vorhanden und umgesetzt (Kennzeichnung, Nutzung, Transport, Speicherung, Rückgabe, Löschung/Vernichtung). +- **Organisatorisch:** Handhabungsmatrix je Klassifizierungsstufe (inkl. Löschung/Vernichtung) definieren und schulen. +- **Technisch:** Technische Kontrollen umsetzen (Verschlüsselung, Zugriffsrechte, sichere Löschung/Datenträgervernichtung) passend zur Stufe. +- **Typische Nachweise:** Handhabungsrichtlinie/-matrix; Lösch-/Vernichtungsnachweise. +- **Vorlage:** R02 +- **Ressourcen:** ISB + IT; ggf. Beschaffung Vernichtungs-/Verschlüsselungslösung. +- **AL-Filter:** AL2 + AL3 + +### 1.3.2-S1 — [SOLL] +**Anforderung:** Die Schutzziele Integrität und Verfügbarkeit werden berücksichtigt. +- **Organisatorisch:** Klassifizierung um Integritäts- und Verfügbarkeitsstufen erweitern; Kriterien definieren. +- **Technisch:** I-/A-Attribute im Inventar; abgeleitete Schutzmaßnahmen (z. B. Backup nach BL-OPS-05) zuordnen. +- **Typische Nachweise:** erweitertes Schema C/I/A; klassifizierte Werte inkl. I/A. +- **Vorlage:** R02; VA-08; BL-OPS-05 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +## Control 1.3.3 — Inwieweit ist sichergestellt, dass nur bewertete und freigegebene externe IT-Dienste genutzt werden? + +### 1.3.3-M1 — [MUSS] +**Anforderung:** Externe IT-Dienste werden nicht ohne ausdrückliche Bewertung und Umsetzung der IS-Anforderungen genutzt; einschlägige Aspekte werden berücksichtigt. +- **Organisatorisch:** Verpflichtende IS-Bewertung vor Nutzung externer IT-Dienste (Cloud/SaaS) im Beschaffungs-/Freigabeprozess verankern. +- **Technisch:** Cloud-/SaaS-Register führen; Nutzung nicht freigegebener Dienste durch Netzwerk-/Proxy-Kontrollen einschränken (Shadow-IT-Erkennung). +- **Typische Nachweise:** Bewertungsdokumente je Dienst; Freigabeliste; Register. +- **Vorlage:** R02 +- **Ressourcen:** ISB + Einkauf/IT; laufend; ggf. CASB/Proxy. +- **AL-Filter:** AL2 + AL3 + +### 1.3.3-M2 — [MUSS] +**Anforderung:** Externe IT-Dienste sind mit dem Schutzbedarf der verarbeiteten Informationswerte abgestimmt. +- **Organisatorisch:** Schutzbedarf der zu verarbeitenden Daten dem Dienst gegenüberstellen; Eignung dokumentieren. +- **Technisch:** Schutzbedarf/Klassifizierung im Dienstregister mit zulässigen Datenkategorien verknüpfen. +- **Typische Nachweise:** Schutzbedarfs-/Eignungsbewertung je Dienst. +- **Vorlage:** R02 +- **Ressourcen:** ISB + Fachbereich; je Dienst. +- **AL-Filter:** AL2 + AL3 + +### 1.3.3-S1 — [SOLL] +**Anforderung:** Anforderungen an Beschaffung, Inbetriebnahme und Freigabe externer IT-Dienste sind bestimmt und erfüllt. +- **Organisatorisch:** IS-Anforderungen in Beschaffungs-/Onboarding-Checklisten für externe Dienste aufnehmen. +- **Technisch:** Konfigurations-/Sicherheitsvorgaben (z. B. SSO, Verschlüsselung) bei Inbetriebnahme prüfen. +- **Typische Nachweise:** Beschaffungs-/Freigabecheckliste; Inbetriebnahme-Doku. +- **Vorlage:** R02 +- **Ressourcen:** Einkauf + IT + ISB; je Dienst. +- **AL-Filter:** AL2 + AL3 + +### 1.3.3-S2 — [SOLL] +**Anforderung:** Ein Verfahren zur Freigabe unter Berücksichtigung des Schutzbedarfs ist etabliert. +- **Organisatorisch:** Formalen Freigabe-Workflow mit Rollen und Entscheidungskriterien definieren. +- **Technisch:** Freigabe-Workflow im Ticket-/Service-Management abbilden. +- **Typische Nachweise:** dokumentiertes Freigabeverfahren; Freigabetickets. +- **Vorlage:** R02 +- **Ressourcen:** ISB + IT; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.3.3-S3 — [SOLL] +**Anforderung:** Externe IT-Dienste und ihre Freigabe sind dokumentiert. +- **Organisatorisch:** Zentrales, aktuelles Register freigegebener Dienste mit Freigabestatus führen. +- **Technisch:** Register im GRC-/Service-Tool mit Freigabehistorie. +- **Typische Nachweise:** Dienstregister mit Freigabestatus. +- **Vorlage:** R02 +- **Ressourcen:** ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.3.3-S4 — [SOLL] +**Anforderung:** Es wird regelmäßig überprüft, dass nur freigegebene externe IT-Dienste genutzt werden. +- **Organisatorisch:** Periodische Reviews/Abgleich der tatsächlichen Nutzung gegen die Freigabeliste durchführen. +- **Technisch:** Shadow-IT-/CASB-Reports oder Proxy-Logauswertung nutzen. +- **Typische Nachweise:** Review-Protokolle; Shadow-IT-Reports. +- **Vorlage:** R02; VA-15 +- **Ressourcen:** IT + ISB; periodisch. +- **AL-Filter:** AL2 + AL3 + +## Control 1.3.4 — Inwieweit ist sichergestellt, dass nur bewertete und freigegebene Software genutzt wird? + +### 1.3.4-M1 — [MUSS] +**Anforderung:** Software wird vor Installation/Nutzung freigegeben; einschlägige Aspekte werden berücksichtigt. +- **Organisatorisch:** Softwarefreigabeprozess (Bewertung Herkunft, Lizenz, Sicherheit) definieren und verpflichtend machen. +- **Technisch:** Application-Whitelisting/Allowlisting und Softwareverteilung über zentrales Endpoint-/Client-Management. +- **Typische Nachweise:** Freigabeliste zugelassener Software; Whitelisting-Konfiguration. +- **Vorlage:** R02 +- **Ressourcen:** IT + ISB; ggf. Endpoint-Management/Whitelisting-Tool. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-M2 — [MUSS] +**Anforderung:** Die Softwarefreigabe gilt auch für Spezialsoftware wie Wartungswerkzeuge. +- **Organisatorisch:** Wartungs-/Diagnose- und Spezialwerkzeuge explizit in den Freigabeprozess einbeziehen. +- **Technisch:** Kontrollierte Bereitstellung von Wartungssoftware (dedizierte Konten/Systeme, Freigabe je Einsatz). +- **Typische Nachweise:** Freigabeliste inkl. Spezialsoftware; Einsatz-/Freigabedoku. +- **Vorlage:** R02 +- **Ressourcen:** IT + ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-S1 — [SOLL] +**Anforderung:** Die zu verwaltenden Softwarearten (Firmware, Betriebssysteme, Anwendungen, Bibliotheken, Gerätetreiber) sind bestimmt. +- **Organisatorisch:** Geltungsbereich des Software-Managements je Softwareart festlegen. +- **Technisch:** Kategorisierung im Software-Inventar/CMDB abbilden. +- **Typische Nachweise:** Übersicht verwalteter Softwarearten. +- **Vorlage:** R02 +- **Ressourcen:** IT; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-S2 — [SOLL] +**Anforderung:** Repositorys der verwalteten Software existieren. +- **Organisatorisch:** Verbindliche zentrale Software-Quellen definieren. +- **Technisch:** Zentrales Software-Repository/Paketquelle (Distributionspunkt) bereitstellen. +- **Typische Nachweise:** Repository-Übersicht; Verweis auf Distributionspunkt. +- **Vorlage:** R02 +- **Ressourcen:** IT; ggf. Repository-Tool. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-S3 — [SOLL] +**Anforderung:** Die Software-Repositorys sind gegen unbefugte Manipulation geschützt. +- **Organisatorisch:** Zugriff auf Repositorys nach Least-Privilege regeln; Änderungen protokollieren. +- **Technisch:** Zugriffsschutz, Integritätsprüfung (Signaturen/Hashes), Protokollierung. +- **Typische Nachweise:** Berechtigungskonzept Repository; Integritäts-/Signaturnachweise. +- **Vorlage:** R02; BL-IAM-05 +- **Ressourcen:** IT; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-S4 — [SOLL] +**Anforderung:** Die Freigabe von Software wird regelmäßig überprüft. +- **Organisatorisch:** Periodisches Review der Freigabeliste (weiterhin benötigt/sicher) durchführen. +- **Technisch:** Report aus Software-Inventar/Whitelisting als Reviewgrundlage. +- **Typische Nachweise:** Review-Protokolle der Softwarefreigaben. +- **Vorlage:** R02; VA-15 +- **Ressourcen:** IT + ISB; periodisch. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-S5 — [SOLL] +**Anforderung:** Softwareversionen und Patch-Stände sind bekannt. +- **Organisatorisch:** Verantwortlichkeit für Versions-/Patchstand-Überblick festlegen. +- **Technisch:** Inventarisierung von Version/Patch via Endpoint-Management/Discovery. +- **Typische Nachweise:** Versions-/Patchstand-Report aus dem Inventar. +- **Vorlage:** R02 +- **Ressourcen:** IT; laufend; ggf. Discovery-Tool. +- **AL-Filter:** AL2 + AL3 + +### 1.3.4-V1 — [SEHR HOCH] +**Anforderung:** Zusätzliche Anforderungen an die Softwarenutzung (z. B. Kontroll-/Überwachungsbedarf) sind, sofern vorhanden, bestimmt. (C, I, A) +- **Organisatorisch:** Für Software mit sehr hohem Schutzbedarf zusätzliche Nutzungs-/Überwachungsauflagen definieren. +- **Technisch:** Erweiterte Protokollierung/Monitoring der Softwarenutzung (z. B. Nutzungslogs, Integritätsüberwachung) umsetzen. +- **Typische Nachweise:** dokumentierte Zusatzanforderungen; Monitoring-/Nutzungsprotokolle. +- **Vorlage:** R02 +- **Ressourcen:** IT + ISB; ggf. Monitoring-Erweiterung. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 1.4.1 — Inwieweit werden Informationssicherheitsrisiken gemanagt? + +### 1.4.1-M1 — [MUSS] +**Anforderung:** Risikobewertungen werden regelmäßig und anlassbezogen durchgeführt. +- **Organisatorisch:** Turnus (z. B. jährlich) und Anlässe (Änderungen, Vorfälle) für Risikobewertungen festlegen. +- **Technisch:** Risikoregister/GRC-Tool mit Terminierung und Wiedervorlagen. +- **Typische Nachweise:** Risikobewertungsberichte; Zeitplan. +- **Vorlage:** R03; VA-09 +- **Ressourcen:** ISB + Risk Owner; periodisch. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-M2 — [MUSS] +**Anforderung:** Risiken werden angemessen bewertet (z. B. Eintrittswahrscheinlichkeit und Schadensausmaß). +- **Organisatorisch:** Bewertungsmethodik (Skalen für Wahrscheinlichkeit/Auswirkung) definieren und anwenden. +- **Technisch:** Methodik im GRC-Tool als Bewertungsschema hinterlegen. +- **Typische Nachweise:** bewertete Risiken mit Wahrscheinlichkeit/Auswirkung; Methodenbeschreibung. +- **Vorlage:** R03; VA-09 +- **Ressourcen:** ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-M3 — [MUSS] +**Anforderung:** Informationssicherheitsrisiken werden dokumentiert. +- **Organisatorisch:** Vollständige, aktuelle Risikodokumentation sicherstellen. +- **Technisch:** Zentrales Risikoregister im GRC-Tool. +- **Typische Nachweise:** Risikoregister. +- **Vorlage:** R03; VA-09 +- **Ressourcen:** ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-M4 — [MUSS] +**Anforderung:** Jedem Risiko ist ein Risk Owner zugeordnet, der für Bewertung und Behandlung verantwortlich ist. +- **Organisatorisch:** Risk Owner je Risiko benennen und Verantwortung kommunizieren. +- **Technisch:** Owner-Feld im Risikoregister pflegen (Pflichtfeld). +- **Typische Nachweise:** Risikoregister mit Owner-Zuordnung. +- **Vorlage:** R03 +- **Ressourcen:** ISB + Fachbereiche; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-S1 — [SOLL] +**Anforderung:** Ein Verfahren zur Identifikation, Bewertung und Behandlung von Sicherheitsrisiken ist vorhanden. +- **Organisatorisch:** Risikomanagement-Verfahren dokumentieren und freigeben. +- **Technisch:** Verfahren im GRC-Tool/DMS verankern. +- **Typische Nachweise:** freigegebenes Risikomanagement-Verfahren. +- **Vorlage:** R03; VA-09 +- **Ressourcen:** ISB; ca. 1–2 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-S2 — [SOLL] +**Anforderung:** Kriterien für Bewertung und Behandlung von Sicherheitsrisiken existieren. +- **Organisatorisch:** Akzeptanzkriterien/Risikoappetit und Behandlungskriterien festlegen und freigeben. +- **Technisch:** Kriterien/Schwellenwerte im GRC-Tool hinterlegen. +- **Typische Nachweise:** Kriterienkatalog; Risikoakzeptanzkriterien. +- **Vorlage:** R03 +- **Ressourcen:** ISB + Leitung; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-S3 — [SOLL] +**Anforderung:** Behandlungsmaßnahmen und Verantwortliche sind festgelegt und dokumentiert; ein Maßnahmenplan wird nachverfolgt. +- **Organisatorisch:** Risikobehandlungsplan mit Maßnahmen, Verantwortlichen und Terminen führen. +- **Technisch:** Maßnahmen-Tracking im GRC-Tool mit Statusverfolgung. +- **Typische Nachweise:** Risikobehandlungsplan; Maßnahmenstatus. +- **Vorlage:** R03 +- **Ressourcen:** ISB + Risk Owner; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.4.1-S4 — [SOLL] +**Anforderung:** Bei Umfeldänderungen (Organisationsstruktur, Standort, Regularien) erfolgt zeitnah eine Neubewertung. +- **Organisatorisch:** Trigger für anlassbezogene Neubewertung definieren und in Change-Prozesse einbinden. +- **Technisch:** Change-/Ereignis-gekoppelte Erinnerung zur Risiko-Neubewertung. +- **Typische Nachweise:** dokumentierte anlassbezogene Neubewertungen. +- **Vorlage:** R03; VA-09 +- **Ressourcen:** ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +## Control 1.5.1 — Inwieweit wird die Einhaltung von Informationssicherheit überprüft (interne Compliance)? + +### 1.5.1-M1 — [MUSS] +**Anforderung:** Die Einhaltung der Richtlinien wird organisationsweit überprüft. +- **Organisatorisch:** Regelmäßige Compliance-Prüfungen/interne Audits über alle Bereiche planen und durchführen. +- **Technisch:** Prüfergebnisse im GRC-Tool erfassen. +- **Typische Nachweise:** Auditplan; Prüf-/Auditberichte. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB/Interne Revision; periodisch. +- **AL-Filter:** AL2 + AL3 + +### 1.5.1-M2 — [MUSS] +**Anforderung:** Richtlinien und Verfahren werden regelmäßig überprüft. +- **Organisatorisch:** Review-Zyklen je Dokument festlegen und nachhalten. +- **Technisch:** Wiedervorlage/Review-Reminder im DMS/GRC. +- **Typische Nachweise:** Review-Historie der Dokumente. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.5.1-M3 — [MUSS] +**Anforderung:** Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt. +- **Organisatorisch:** Abweichungs-/Maßnahmenmanagement (CAPA) mit Verantwortlichen und Fristen etablieren. +- **Technisch:** Findings/Maßnahmen im GRC-Tool nachverfolgen. +- **Typische Nachweise:** Maßnahmenliste zu Findings; Statusnachverfolgung. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB + Fachbereiche; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.5.1-M4 — [MUSS] +**Anforderung:** Die Einhaltung von IS-Anforderungen (z. B. technische Vorgaben) wird regelmäßig überprüft. +- **Organisatorisch:** Technische Compliance-Prüfungen (Konfiguration/Baseline-Konformität) planen. +- **Technisch:** Automatisierte Compliance-/Konfigurations-Scans gegen Baseline-Vorgaben (BL-*). +- **Typische Nachweise:** Scan-/Konformitätsberichte; Abweichungslisten. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** IT + ISB; ggf. Compliance-Scan-Tool. +- **AL-Filter:** AL2 + AL3 + +### 1.5.1-M5 — [MUSS] +**Anforderung:** Ergebnisse der Überprüfungen werden aufgezeichnet und aufbewahrt. +- **Organisatorisch:** Aufbewahrungsfristen für Prüfergebnisse festlegen. +- **Technisch:** Revisionssichere Ablage der Berichte im DMS/GRC. +- **Typische Nachweise:** archivierte Prüfberichte; Ablage-/Aufbewahrungsnachweis. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.5.1-S1 — [SOLL] +**Anforderung:** Ein Plan für Inhalt und Rahmenbedingungen (Zeitplan, Umfang, Controls) der Überprüfungen liegt vor. +- **Organisatorisch:** Mehrjahres-/Jahresauditplan mit Scope und Terminen erstellen und freigeben. +- **Technisch:** Auditplan im GRC-Tool mit Terminplanung. +- **Typische Nachweise:** freigegebener Prüf-/Auditplan. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +## Control 1.5.2 — Inwieweit wird die Informationssicherheit durch unabhängige Stellen überprüft? + +### 1.5.2-M1 — [MUSS] +**Anforderung:** IS-Überprüfungen werden durch eine unabhängige und kompetente Stelle regelmäßig und nach grundlegenden Änderungen durchgeführt. +- **Organisatorisch:** Unabhängige Prüfinstanz (interne Revision oder externer Prüfer) beauftragen; Unabhängigkeit sicherstellen; Turnus/Anlässe festlegen. +- **Technisch:** Prüfergebnisse zentral im GRC-Tool dokumentieren. +- **Typische Nachweise:** unabhängige Prüf-/Auditberichte; Beauftragung/Unabhängigkeitsnachweis. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB + interne Revision/externer Auditor; Prüfbudget möglich. +- **AL-Filter:** AL2 + AL3 + +### 1.5.2-M2 — [MUSS] +**Anforderung:** Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt. +- **Organisatorisch:** Findings der unabhängigen Prüfung in das Maßnahmenmanagement überführen und nachhalten. +- **Technisch:** Maßnahmen-Tracking im GRC-Tool. +- **Typische Nachweise:** Maßnahmenliste zu Prüf-Findings; Statusnachverfolgung. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB + Fachbereiche; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.5.2-S1 — [SOLL] +**Anforderung:** Ergebnisse der Überprüfungen werden dokumentiert und der Organisationsleitung berichtet. +- **Organisatorisch:** Berichtsweg an die Leitung (z. B. im Management-Review) etablieren. +- **Technisch:** Berichte/Reportings im GRC-Tool bereitstellen. +- **Typische Nachweise:** Prüfbericht mit Leitungsvorlage; Management-Review-Protokoll. +- **Vorlage:** R03; VA-15 +- **Ressourcen:** ISB; gering, periodisch. +- **AL-Filter:** AL2 + AL3 + +## Control 1.6.1 — Inwieweit werden Sicherheitsereignisse gemeldet? + +### 1.6.1-M1 — [MUSS] +**Anforderung:** Eine Definition für ein meldepflichtiges Sicherheitsereignis/eine Beobachtung existiert und ist bekannt. +- **Organisatorisch:** Definition und Beispiele meldepflichtiger Ereignisse festlegen und kommunizieren. +- **Technisch:** Definition im Intranet/Meldeportal verfügbar machen. +- **Typische Nachweise:** dokumentierte Definition; Kommunikations-/Schulungsnachweis. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-M2 — [MUSS] +**Anforderung:** Angemessene, risikoorientierte Meldemechanismen sind definiert, umgesetzt und bekannt. +- **Organisatorisch:** Meldeprozess und -wege definieren und einführen; Bekanntmachung sicherstellen. +- **Technisch:** Meldekanäle bereitstellen (Ticketsystem, Meldeportal, Hotline/E-Mail). +- **Typische Nachweise:** beschriebener Meldeprozess; eingerichtete Meldekanäle; Kommunikation. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB + IT; ggf. Ticket-/Meldetool. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-M3 — [MUSS] +**Anforderung:** Angemessene Kanäle zur Kommunikation mit Meldenden existieren. +- **Organisatorisch:** Rückkanäle für Rückfragen/Statusinformation an Meldende festlegen. +- **Technisch:** Kommunikationsfunktion im Ticketsystem (Rückmeldungen, Status). +- **Typische Nachweise:** Kommunikationsverlauf im Ticketsystem; Kanalbeschreibung. +- **Vorlage:** R04 +- **Ressourcen:** IT + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-S1 — [SOLL] +**Anforderung:** Eine gemeinsame Anlaufstelle für die Ereignismeldung existiert. +- **Organisatorisch:** Single Point of Contact (z. B. Security-Postfach/Service Desk) benennen. +- **Technisch:** Zentrale Meldeadresse/-portal einrichten. +- **Typische Nachweise:** SPoC-Beschreibung; zentrale Meldeadresse. +- **Vorlage:** R04 +- **Ressourcen:** ISB + IT; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-S2 — [SOLL] +**Anforderung:** Verschiedene Meldekanäle je nach Schwere (Echtzeit für Notfälle, asynchron via Ticket/E-Mail) sind verfügbar. +- **Organisatorisch:** Kanäle nach Schweregrad differenzieren (Hotline vs. Ticket) und kommunizieren. +- **Technisch:** Hotline/Notfallnummer plus asynchrone Kanäle (Ticket, E-Mail) bereitstellen. +- **Typische Nachweise:** Kanalübersicht nach Schweregrad. +- **Vorlage:** R04 +- **Ressourcen:** IT + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-S3 — [SOLL] +**Anforderung:** Beschäftigte sind verpflichtet und geschult, relevante Ereignisse zu melden. +- **Organisatorisch:** Meldepflicht in Richtlinien/Verpflichtung verankern; Schulung/Sensibilisierung durchführen. +- **Technisch:** Schulungsnachweise im Schulungssystem dokumentieren. +- **Typische Nachweise:** Verpflichtung; Schulungs-/Awareness-Nachweise. +- **Vorlage:** R04; VA-12 +- **Ressourcen:** ISB + HR; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-S4 — [SOLL] +**Anforderung:** Sicherheitsereignisse können auch durch Externe gemeldet werden; einschlägige Aspekte werden berücksichtigt. +- **Organisatorisch:** Externen Meldeweg definieren und kommunizieren (Lieferanten, Kunden, Öffentlichkeit). +- **Technisch:** Öffentlich erreichbare Meldeadresse/-formular (ggf. security.txt/Kontaktseite). +- **Typische Nachweise:** externe Kontakt-/Meldemöglichkeit; Prozessbeschreibung. +- **Vorlage:** R04 +- **Ressourcen:** ISB + IT; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-S5 — [SOLL] +**Anforderung:** Mechanismus und Information zur Meldung sind für alle relevanten Meldenden zugänglich. +- **Organisatorisch:** Zugänglichkeit der Meldeinformation für alle Zielgruppen sicherstellen. +- **Technisch:** Meldeinformationen an zentralen, jederzeit erreichbaren Stellen (Intranet, Portal) veröffentlichen. +- **Typische Nachweise:** veröffentlichte Meldeanleitung; Zugriffsnachweis. +- **Vorlage:** R04 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-S6 — [SOLL] +**Anforderung:** Ein Rückmeldeverfahren an die Meldenden ist etabliert. +- **Organisatorisch:** Feedback-/Statusrückmeldung an Meldende verbindlich festlegen. +- **Technisch:** Automatische Eingangs-/Statusbenachrichtigung im Ticketsystem. +- **Typische Nachweise:** Rückmeldungen/Benachrichtigungen; Prozessbeschreibung. +- **Vorlage:** R04 +- **Ressourcen:** IT + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.1-V1 — [SEHR HOCH] +**Anforderung:** Tests und Übungen der Ereignis- und Beobachtungsmeldung werden regelmäßig durchgeführt. (C, I, A) +- **Organisatorisch:** Regelmäßige Meldeübungen (z. B. Phishing-Simulation, Testmeldungen) planen und auswerten. +- **Technisch:** Simulations-/Testmeldungen über die Meldekanäle auslösen und Ergebnisse auswerten. +- **Typische Nachweise:** Übungsplan; Übungs-/Auswertungsberichte. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB; periodisch; ggf. Awareness-/Simulationstool. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 1.6.2 — Inwieweit werden gemeldete Sicherheitsereignisse gemanagt? + +### 1.6.2-M1 — [MUSS] +**Anforderung:** Gemeldete Ereignisse werden ohne unangemessene Verzögerung bearbeitet. +- **Organisatorisch:** Bearbeitungsprozess mit Erstreaktion und Verantwortlichen definieren. +- **Technisch:** Ticket-/Incident-Workflow mit Eingangs- und Bearbeitungsstatus. +- **Typische Nachweise:** Incident-Tickets mit Zeitstempeln; Prozessbeschreibung. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB/Incident-Team; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.6.2-M2 — [MUSS] +**Anforderung:** Eine angemessene Reaktion auf gemeldete Sicherheitsereignisse ist sichergestellt. +- **Organisatorisch:** Reaktions-/Behandlungsverfahren (Analyse, Eindämmung, Behebung) festlegen. +- **Technisch:** Incident-Response-Workflow und ggf. Playbooks im Tool hinterlegen. +- **Typische Nachweise:** dokumentierte Vorfallbehandlung; Abschluss-/Behebungsnachweis. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** Incident-Team; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.6.2-M3 — [MUSS] +**Anforderung:** Lessons Learned fließen in die kontinuierliche Verbesserung ein. +- **Organisatorisch:** Nachbereitung (Post-Incident-Review) mit Ableitung von Verbesserungen durchführen. +- **Technisch:** Verbesserungsmaßnahmen im GRC-/Maßnahmentool nachverfolgen. +- **Typische Nachweise:** Lessons-Learned-/Post-Incident-Protokolle; abgeleitete Maßnahmen. +- **Vorlage:** R04 +- **Ressourcen:** ISB + Incident-Team; je Vorfall. +- **AL-Filter:** AL2 + AL3 + +### 1.6.2-S1 — [SOLL] +**Anforderung:** Gemeldete Ereignisse werden kategorisiert, qualifiziert und priorisiert. +- **Organisatorisch:** Kategorien, Qualifizierungen und Prioritätsstufen definieren und anwenden. +- **Technisch:** Klassifizierungsfelder/Priorisierung im Ticket-/Incident-System. +- **Typische Nachweise:** kategorisierte/priorisierte Tickets; Klassifizierungsschema. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** Incident-Team; laufend. +- **AL-Filter:** AL2 + AL3 + +### 1.6.2-S2 — [SOLL] +**Anforderung:** Verantwortlichkeiten für die Behandlung je Kategorie sind definiert und zugewiesen. +- **Organisatorisch:** Zuständigkeiten je Ereigniskategorie festlegen (RACI/Eskalationsmatrix). +- **Technisch:** Zuweisungsregeln im Ticketsystem (Routing/Queues). +- **Typische Nachweise:** Zuständigkeitsmatrix; Ticket-Routing-Konfiguration. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.2-S3 — [SOLL] +**Anforderung:** Eine Strategie zur Meldung potenziell strafrechtlich relevanter Aspekte an Behörden existiert. (C, I, A) +- **Organisatorisch:** Vorgehen und Zuständigkeit für Behördenmeldungen (Legal/Datenschutz einbinden) festlegen. +- **Technisch:** Kontaktinformationen/Vorlagen im Incident-Prozess hinterlegen. +- **Typische Nachweise:** dokumentierte Meldestrategie; Behördenkontaktliste. +- **Vorlage:** R04 +- **Ressourcen:** ISB + Legal; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.2-H1 — [HOCH] +**Anforderung:** Maximale Reaktionszeiten je Klasse, Kategorie und Schwere sind definiert. (C, I, A) +- **Organisatorisch:** SLA/Reaktionszeiten je Priorität/Kategorie festlegen und freigeben. +- **Technisch:** SLA-Zeiten und Timer/Eskalation im Ticketsystem konfigurieren. +- **Typische Nachweise:** SLA-Matrix; SLA-Konfiguration im Tool. +- **Vorlage:** R04 +- **Ressourcen:** ISB + IT; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.2-H2 — [HOCH] +**Anforderung:** Nicht prioritätsgerecht bearbeitete Ereignisse werden eskaliert; einschlägige Aspekte werden berücksichtigt. (C, I, A) +- **Organisatorisch:** Eskalationswege und -stufen definieren. +- **Technisch:** Automatische SLA-Eskalation bei Fristüberschreitung im Ticketsystem. +- **Typische Nachweise:** Eskalationskonzept; dokumentierte Eskalationen. +- **Vorlage:** R04 +- **Ressourcen:** IT + ISB; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.2-H3 — [HOCH] +**Anforderung:** Gesetzliche, regulatorische und vertragliche Meldepflichten sowie Kontaktinformationen sind bekannt. (C, I, A) +- **Organisatorisch:** Meldepflichten (z. B. Datenschutz, Kundenverträge) mit Fristen und Kontakten zusammenstellen. +- **Technisch:** Melderegister/Kontaktliste im Incident-Prozess bereitstellen. +- **Typische Nachweise:** Melderegister; Kontaktliste; Vertrags-/Rechtsbezug. +- **Vorlage:** R04 +- **Ressourcen:** ISB + Legal; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.2-H4 — [HOCH] +**Anforderung:** Eine Kommunikationsstrategie für sicherheitsrelevante Ereignisse existiert; einschlägige Aspekte werden berücksichtigt. (C, I, A) +- **Organisatorisch:** Interne/externe Kommunikationsstrategie (Sprecher, Zielgruppen, Freigaben) definieren. +- **Technisch:** Kommunikationsvorlagen/Verteiler hinterlegen. +- **Typische Nachweise:** Kommunikationsstrategie/-plan; Vorlagen. +- **Vorlage:** R04 +- **Ressourcen:** ISB + Kommunikation; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.2-H5 — [HOCH] +**Anforderung:** Verfahren zur Reaktion auf Sicherheitsvorfälle bei Lieferanten sind etabliert; einschlägige Aspekte werden berücksichtigt. (C, I, A) +- **Organisatorisch:** Meldepflichten und Reaktionsprozesse mit Lieferanten vertraglich vereinbaren und im Incident-Prozess berücksichtigen. +- **Technisch:** Lieferanten-Kontakte/Schnittstellen im Incident-Tool erfassen. +- **Typische Nachweise:** Lieferanten-Vorfallverfahren; vertragliche Meldeklauseln. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB + Einkauf; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.2-V1 — [SEHR HOCH] +**Anforderung:** Die Behandlung von Ereignissen unterschiedlicher Kategorien und Prioritäten wird regelmäßig getestet; einschlägige Aspekte werden berücksichtigt. (A) +- **Organisatorisch:** Regelmäßige Incident-Response-Übungen über verschiedene Kategorien/Prioritäten planen und auswerten. +- **Technisch:** Testszenarien über den Incident-Workflow durchspielen; Ergebnisse dokumentieren. +- **Typische Nachweise:** Übungsplan; Übungs-/Testberichte. +- **Vorlage:** R04; VA-01 +- **Ressourcen:** ISB + Incident-Team; periodisch. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 1.6.3 — Inwieweit werden Krisen gemanagt? + +### 1.6.3-M1 — [MUSS] +**Anforderung:** Ein angemessener Plan zur Reaktion auf und Bewältigung von Krisensituationen existiert; erforderliche Ressourcen sind verfügbar. +- **Organisatorisch:** Krisenmanagementplan mit Rollen, Abläufen und Ressourcen erstellen und freigeben. +- **Technisch:** Plan und Kontaktdaten redundant/offline verfügbar halten. +- **Typische Nachweise:** freigegebener Krisenmanagementplan; Ressourcenübersicht. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB + Leitung; ca. 2–3 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-M2 — [MUSS] +**Anforderung:** Verantwortlichkeiten und Befugnisse für das Krisenmanagement sind definiert, dokumentiert und zugewiesen. +- **Organisatorisch:** Krisenrollen und Entscheidungsbefugnisse festlegen und namentlich zuweisen. +- **Technisch:** Rollen-/Kontaktverzeichnis im Krisenplan hinterlegen. +- **Typische Nachweise:** Rollen-/Befugnismatrix; Krisenorganigramm. +- **Vorlage:** R04 +- **Ressourcen:** Leitung + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-M3 — [MUSS] +**Anforderung:** Die verantwortlichen Beschäftigten sind definiert und für ihre Aufgabe qualifiziert. +- **Organisatorisch:** Qualifikation der Krisenverantwortlichen sicherstellen (Schulung/Training). +- **Technisch:** Qualifikations-/Trainingsnachweise dokumentieren. +- **Typische Nachweise:** Benennungen; Schulungs-/Trainingsnachweise. +- **Vorlage:** R04; VA-12 +- **Ressourcen:** HR + ISB; Schulungsbudget. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-S1 — [SOLL] +**Anforderung:** Methoden zur Erkennung von Krisensituationen sind etabliert; Anzeichen und vorhersehbare Krisen sind identifiziert. +- **Organisatorisch:** Frühwarnindikatoren und Erkennungskriterien definieren. +- **Technisch:** Monitoring/Meldeschwellen zur Krisenerkennung einbinden. +- **Typische Nachweise:** Indikatoren-/Erkennungskatalog. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-S2 — [SOLL] +**Anforderung:** Ein Verfahren zur Auslösung und/oder Eskalation des Krisenmanagements ist vorhanden. +- **Organisatorisch:** Alarmierungs-/Eskalationsverfahren mit Auslösekriterien festlegen. +- **Technisch:** Alarmierungsweg/-tool (Notfallbenachrichtigung) bereitstellen. +- **Typische Nachweise:** Alarmierungs-/Eskalationsverfahren. +- **Vorlage:** R04 +- **Ressourcen:** ISB; ggf. Alarmierungstool. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-S3 — [SOLL] +**Anforderung:** Strategische Ziele und ihre Priorität in Krisensituationen sind definiert und bekannt. +- **Organisatorisch:** Krisenziele und Prioritäten (z. B. Schutz von Leben, Kernprozessen) festlegen und kommunizieren. +- **Technisch:** Ziele im Krisenplan dokumentieren. +- **Typische Nachweise:** dokumentierte Krisenziele/Prioritäten. +- **Vorlage:** R04 +- **Ressourcen:** Leitung + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-S4 — [SOLL] +**Anforderung:** Ein Krisenstab ist definiert und genehmigt. +- **Organisatorisch:** Zusammensetzung, Aufgaben und Stellvertretung des Krisenstabs festlegen und genehmigen. +- **Technisch:** Krisenstab-Kontaktliste redundant vorhalten. +- **Typische Nachweise:** genehmigte Krisenstab-Definition; Besetzungsliste. +- **Vorlage:** R04 +- **Ressourcen:** Leitung + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-S5 — [SOLL] +**Anforderung:** Krisenrichtlinien und -verfahren sind definiert und genehmigt. +- **Organisatorisch:** Krisenrichtlinien/-verfahren dokumentieren und freigeben. +- **Technisch:** Verfahren im DMS und offline verfügbar halten. +- **Typische Nachweise:** freigegebene Krisenrichtlinien/-verfahren. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-S6 — [SOLL] +**Anforderung:** Die Krisenplanung wird regelmäßig überprüft und aktualisiert. +- **Organisatorisch:** Review-Zyklus für die Krisenplanung festlegen. +- **Technisch:** Wiedervorlage/Review-Reminder im DMS. +- **Typische Nachweise:** Review-Historie der Krisenplanung. +- **Vorlage:** R04; VA-15 +- **Ressourcen:** ISB; gering, periodisch. +- **AL-Filter:** AL2 + AL3 + +### 1.6.3-H1 — [HOCH] +**Anforderung:** Relevante unterschiedliche potenzielle Krisenszenarien sind identifiziert. +- **Organisatorisch:** Szenarienkatalog (z. B. Ausfall, Cyberangriff, Standortverlust) erstellen. +- **Technisch:** Szenarien im Krisenplan/BCM-Tool dokumentieren. +- **Typische Nachweise:** Krisenszenarien-Katalog. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.3-H2 — [HOCH] +**Anforderung:** Notwendige Ressourcen und Informationen zur Krisenbewältigung sind identifiziert; Maßnahmen zur Sicherstellung der Verfügbarkeit/Ausfallplanung sind vorhanden. (A) +- **Organisatorisch:** Kritische Ressourcen (Kommunikation, Kontakt-/Risikoinfos) bestimmen und Ausfallplanung erstellen. +- **Technisch:** Redundante Kommunikationsinfrastruktur; Offline-Verfügbarkeit von Kontakt-/Risikoinformationen; Backup (BL-OPS-05). +- **Typische Nachweise:** Ressourcenliste; Ausfall-/Redundanzkonzept. +- **Vorlage:** R04; BL-OPS-05 +- **Ressourcen:** ISB + IT; ggf. Beschaffung Redundanz. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.3-H3 — [HOCH] +**Anforderung:** Eine Kommunikationsstrategie für Krisensituationen existiert. (A) +- **Organisatorisch:** Krisenkommunikationsstrategie (interne/externe Zielgruppen, Sprecher, Freigaben) definieren. +- **Technisch:** Kommunikationskanäle/-vorlagen und redundante Erreichbarkeit bereitstellen. +- **Typische Nachweise:** Krisenkommunikationsplan; Vorlagen/Verteiler. +- **Vorlage:** R04 +- **Ressourcen:** ISB + Kommunikation; ca. 1 PT. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.3-H4 — [HOCH] +**Anforderung:** Effizienz, Durchführbarkeit und Angemessenheit der Krisenplanung werden regelmäßig bewertet. (A) +- **Organisatorisch:** Bewertungskriterien und Turnus zur Beurteilung der Krisenplanung festlegen. +- **Technisch:** Bewertungsergebnisse dokumentieren und Maßnahmen ableiten. +- **Typische Nachweise:** Bewertungsberichte der Krisenplanung. +- **Vorlage:** R04; VA-15 +- **Ressourcen:** ISB; periodisch. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.3-H5 — [HOCH] +**Anforderung:** Stichprobenbasierte Tests der Krisenplanung werden durchgeführt (z. B. Simulation, Tabletop-Übungen mit Schlüsselpersonal). (A) +- **Organisatorisch:** Tabletop-/Simulationsübungen mit Schlüsselpersonal planen und auswerten. +- **Technisch:** Übungsszenarien vorbereiten; Ergebnisse dokumentieren. +- **Typische Nachweise:** Übungsplan; Übungs-/Auswertungsberichte. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB + Krisenstab; periodisch. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 1.6.3-V1 — [SEHR HOCH] +**Anforderung:** Krisenübungen und Simulationen unter Einbindung aller relevanten Personen einschließlich Entscheidungsträger werden regelmäßig durchgeführt. (A) +- **Organisatorisch:** Umfassende Krisenübungen mit Leitung/Entscheidungsträgern regelmäßig durchführen und nachbereiten. +- **Technisch:** Realitätsnahe Simulationsumgebung/-szenarien inkl. Kommunikationsinfrastruktur einsetzen. +- **Typische Nachweise:** Übungskonzept; Teilnahmenachweise (inkl. Leitung); Auswertungs-/Verbesserungsberichte. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB + Leitung + Krisenstab; periodisch; ggf. externe Übungsbegleitung. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + + +--- + +# Kapitel 2–4 — Personal, Physisch, IAM + +## Control 2.1.1 — Qualifikation und Eignung des Personals + +### 2.1.1-M1 — [MUSS] +**Anforderung:** Sensible Arbeitsbereiche und Tätigkeiten sind bestimmt. +- **Organisatorisch:** Sensible Bereiche/Tätigkeiten (z. B. Administration, Zugang zu Kundennetzen, Fertigung mit Prototypenbezug) in einer Übersicht definieren und den Stellenprofilen zuordnen; Kriterien mit HR und Fachbereichen abstimmen. +- **Technisch:** Zuordnung in der HR-/Berechtigungssystematik hinterlegen, sodass sensible Rollen an erhöhte Prüf- und Berechtigungsanforderungen gekoppelt sind (BL-IAM-04 Rollenmodell). +- **Typische Nachweise:** Liste sensibler Arbeitsbereiche/Tätigkeiten, Stellenprofile mit Sensibilitätskennzeichnung, Freigabevermerk HR/ISB. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR + ISB, gering; einmalige Erhebung, danach Pflege im Onboarding. +- **AL-Filter:** AL2, AL3 + +### 2.1.1-M2 — [MUSS] +**Anforderung:** Die Anforderungen an Beschäftigte hinsichtlich ihrer Stellenprofile sind bestimmt und erfüllt. +- **Organisatorisch:** Je Stellenprofil erforderliche Qualifikationen, Sicherheitsanforderungen und Nachweispflichten definieren und im Einstellungsprozess prüfen. +- **Technisch:** Anforderungsprofile im HR-System/Recruiting-Tool als strukturierte Felder pflegen; Abgleich bei Besetzung dokumentieren. +- **Typische Nachweise:** Stellenbeschreibungen mit Sicherheitsanforderungen, Nachweis der Anforderungsprüfung im Einstellungsakt. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR, gering–mittel; laufend im Recruiting. +- **AL-Filter:** AL2, AL3 + +### 2.1.1-M3 — [MUSS] +**Anforderung:** Die Identität potenzieller Beschäftigter wird verifiziert (z. B. Prüfung von Ausweisdokumenten). +- **Organisatorisch:** Verbindliche Identitätsprüfung (amtliches Ausweisdokument) als Pflichtschritt im Onboarding festlegen; Ergebnis revisionssicher vermerken (ohne unzulässige Kopien). +- **Technisch:** Prüfvermerk im HR-System dokumentieren; ggf. Identverfahren des Dienstleisters nutzen. +- **Typische Nachweise:** Onboarding-Checkliste mit Feld „Identität geprüft", Prüfvermerk, Prozessbeschreibung. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR, gering; je Einstellung. +- **AL-Filter:** AL2, AL3 + +### 2.1.1-S1 — [SOLL] +**Anforderung:** Die persönliche Eignung potenzieller Beschäftigter wird mit einfachen Methoden überprüft (z. B. Vorstellungsgespräch). +- **Organisatorisch:** Strukturiertes Vorstellungsgespräch mit Eignungsbewertung als Standardschritt etablieren; Bewertungsraster verwenden. +- **Technisch:** Bewertung im Recruiting-Tool dokumentieren. +- **Typische Nachweise:** Interviewleitfaden, dokumentierte Eignungsbewertung. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR/Fachbereich, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.1-S2 — [SOLL] +**Anforderung:** Eine erweiterte Eignungsprüfung abhängig vom Arbeitsbereich wird durchgeführt (z. B. Referenzen, Zeugnisse, Führungszeugnis). +- **Organisatorisch:** Für sensible Tätigkeiten (aus M1) erweiterte Prüfschritte festlegen (Referenz-/Zeugnisprüfung, Führungszeugnis) unter Beachtung arbeits- und datenschutzrechtlicher Grenzen. +- **Technisch:** Prüfumfang je Sensibilitätsstufe im HR-System hinterlegen; Nachweise fristgerecht und datensparsam ablegen. +- **Typische Nachweise:** Prüfkonzept nach Sensibilitätsstufe, dokumentierte Referenz-/Zeugnisprüfung, Vermerk Führungszeugnis. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR + Datenschutz, mittel; nur für sensible Rollen. +- **AL-Filter:** AL2, AL3 + +## Control 2.1.2 — Verpflichtung der Beschäftigten + +### 2.1.2-M1 — [MUSS] +**Anforderung:** Eine Vertraulichkeitsverpflichtung ist in Kraft. +- **Organisatorisch:** Vertraulichkeitsverpflichtung (NDA/Verschwiegenheit) verpflichtend bei Eintritt unterzeichnen lassen; Nachhalten der Unterschriften. +- **Technisch:** Signierte Verpflichtungen im Personalakten-/DMS-System ablegen; Status je Beschäftigtem nachvollziehbar. +- **Typische Nachweise:** Unterzeichnete Vertraulichkeitsverpflichtungen, Vollständigkeitsübersicht. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR, gering; je Eintritt. +- **AL-Filter:** AL2, AL3 + +### 2.1.2-M2 — [MUSS] +**Anforderung:** Eine Verpflichtung zur Einhaltung der Informationssicherheitsrichtlinien ist in Kraft. +- **Organisatorisch:** Verpflichtung zur Einhaltung der IS-Richtlinien in Arbeitsvertrag oder gesonderte Erklärung aufnehmen; bei Richtlinienänderung erneut bestätigen lassen. +- **Technisch:** Bestätigung über HR-Portal/LMS mit Zeitstempel erfassen. +- **Typische Nachweise:** Unterzeichnete Verpflichtungserklärung, Zustimmungsprotokoll im Portal. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.2-S1 — [SOLL] +**Anforderung:** Eine über den Arbeitsvertrag hinausgehende Vertraulichkeitsverpflichtung ist in Kraft. +- **Organisatorisch:** Für Rollen mit Zugang zu hoch klassifizierten oder Kundeninformationen ergänzende NDAs (auch nachvertraglich) vorsehen. +- **Technisch:** Zuordnung erweiterter NDAs zu sensiblen Rollen im HR-System. +- **Typische Nachweise:** Ergänzende NDA-Vorlage, unterzeichnete Zusatzvereinbarungen. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR + Recht, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.2-S2 — [SOLL] +**Anforderung:** Informationssicherheitsaspekte werden in den Arbeitsverträgen der Beschäftigten berücksichtigt. +- **Organisatorisch:** Standard-IS-Klauseln (Geheimhaltung, Richtlinientreue, Rückgabepflichten, Konsequenzen) mit HR/Recht in Vertragsmuster verankern. +- **Technisch:** Zentrale Vertragsvorlagen im DMS versionieren. +- **Typische Nachweise:** Vertragsmuster mit IS-Klauseln, Freigabe Recht. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR + Recht, gering; einmalig. +- **AL-Filter:** AL2, AL3 + +### 2.1.2-S3 — [SOLL] +**Anforderung:** Ein Verfahren zum Umgang mit Verstößen gegen diese Verpflichtungen ist beschrieben. +- **Organisatorisch:** Eskalations- und Sanktionsprozess (Disziplinarmaßnahmen) mit HR, Betriebsrat und Recht definieren und kommunizieren. +- **Technisch:** Fälle im HR-/Vorfallsystem nachvollziehbar dokumentieren. +- **Typische Nachweise:** Verfahrensbeschreibung Verstöße, Sanktionskatalog, ggf. dokumentierte Fälle. +- **Vorlage:** R05; VA-14 +- **Ressourcen:** HR + Recht, gering; einmalig, danach anlassbezogen. +- **AL-Filter:** AL2, AL3 + +## Control 2.1.3 — Sensibilisierung und Schulung + +### 2.1.3-M1 — [MUSS] +**Anforderung:** Beschäftigte werden geschult und sensibilisiert. +- **Organisatorisch:** Verpflichtende IS-Awareness-Schulung bei Eintritt und mindestens jährlich; Teilnahme nachhalten und mahnen. +- **Technisch:** Schulungsdurchführung und -nachweis über LMS/Awareness-Plattform, inkl. Erinnerungen. +- **Typische Nachweise:** Schulungsnachweise/Teilnahmequote, Schulungsinhalte, Einladungs-/Mahnprotokolle. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** ISB + HR, mittel; Plattform ggf. zu beschaffen (Awareness-Tool) — führt zu Aufgabe. +- **AL-Filter:** AL2, AL3 + +### 2.1.3-S1 — [SOLL] +**Anforderung:** Ein Konzept für Sensibilisierung und Schulung der Beschäftigten ist erstellt. +- **Organisatorisch:** Awareness-Konzept mit Zielen, Inhalten, Turnus, Formaten und Erfolgskontrolle dokumentieren. +- **Technisch:** Konzept im DMS versionieren; Kennzahlen aus dem LMS ableiten. +- **Typische Nachweise:** Awareness-/Schulungskonzept, Jahresplan. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** ISB, gering–mittel; einmalig, jährliche Fortschreibung. +- **AL-Filter:** AL2, AL3 + +### 2.1.3-S2 — [SOLL] +**Anforderung:** Zielgruppen für Schulungs- und Sensibilisierungsmaßnahmen sind identifiziert und im Konzept berücksichtigt. +- **Organisatorisch:** Zielgruppen (Führungskräfte, Administratoren, Beschäftigte mit Kundennetzzugang, Fertigung) mit spezifischen Inhalten definieren. +- **Technisch:** Zielgruppen-Zuordnung und differenzierte Lernpfade im LMS abbilden. +- **Typische Nachweise:** Zielgruppenmatrix, rollenspezifische Curricula. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** ISB, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.3-S3 — [SOLL] +**Anforderung:** Das Konzept ist durch die verantwortliche Leitung genehmigt. +- **Organisatorisch:** Formale Freigabe des Awareness-Konzepts durch die Leitung einholen und dokumentieren. +- **Technisch:** Freigabevermerk/Signatur im DMS. +- **Typische Nachweise:** Freigabeprotokoll/Managementunterschrift. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** Leitung + ISB, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.3-S4 — [SOLL] +**Anforderung:** Schulungs- und Sensibilisierungsmaßnahmen werden regelmäßig und anlassbezogen durchgeführt. +- **Organisatorisch:** Jahresturnus plus anlassbezogene Maßnahmen (z. B. nach Vorfällen, neuen Bedrohungen) festlegen. +- **Technisch:** Kampagnen (z. B. Phishing-Simulation) und Turnusschulungen über die Awareness-Plattform steuern. +- **Typische Nachweise:** Durchführungsnachweise, Kampagnenauswertungen. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** ISB, mittel; laufend. +- **AL-Filter:** AL2, AL3 + +### 2.1.3-S5 — [SOLL] +**Anforderung:** Die Teilnahme an Schulungs- und Sensibilisierungsmaßnahmen wird dokumentiert. +- **Organisatorisch:** Teilnahmepflicht und Nachverfolgung nicht abgeschlossener Schulungen regeln. +- **Technisch:** Automatische Teilnahme-/Abschlussdokumentation im LMS mit Reporting. +- **Typische Nachweise:** Teilnahmelisten/Abschlussberichte, Quotenauswertung. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** ISB/HR, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.3-S6 — [SOLL] +**Anforderung:** Ansprechpartner für Informationssicherheit sind den Beschäftigten bekannt. +- **Organisatorisch:** ISB/Kontaktwege in Onboarding, Intranet und Schulungen kommunizieren. +- **Technisch:** Kontaktseite/Meldekanal im Intranet prominent verlinken. +- **Typische Nachweise:** Intranet-Seite, Onboarding-Unterlagen mit Ansprechpartnern. +- **Vorlage:** R05; VA-12 +- **Ressourcen:** ISB, gering. +- **AL-Filter:** AL2, AL3 + +## Control 2.1.4 — Mobiles Arbeiten + +### 2.1.4-M1 — [MUSS] +**Anforderung:** Die Anforderungen an mobiles Arbeiten sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +- **Organisatorisch:** Richtlinie mobiles Arbeiten/Homeoffice mit Regeln zu Umgebung, Umgang mit Informationen, VPN-Pflicht und Meldewegen erstellen und verbindlich machen. +- **Technisch:** Sichere Fernzugriffe (VPN/ZTNA), verschlüsselte Endgeräte und MDM-gestützte Richtliniendurchsetzung (BL-EUC-01 Endgeräteschutz). +- **Typische Nachweise:** Richtlinie mobiles Arbeiten, VPN-/MDM-Konfiguration, Kenntnisnahmen. +- **Vorlage:** R06 +- **Ressourcen:** ISB + IT, mittel; VPN/MDM ggf. auszubauen — führt zu Aufgabe. +- **AL-Filter:** AL2, AL3 + +### 2.1.4-S1 — [SOLL] +**Anforderung:** Die einschlägigen Aspekte des mobilen Arbeitens werden berücksichtigt. +- **Organisatorisch:** Aspekte wie Clean Desk unterwegs, Nutzung öffentlicher Netze, Umgang mit vertraulichen Gesprächen und Papierdokumenten in der Richtlinie konkretisieren. +- **Technisch:** Automatische Bildschirmsperre, Festplattenverschlüsselung und Netzwerkabsicherung technisch erzwingen (BL-EUC-01). +- **Typische Nachweise:** Richtlinienabschnitt mit Aspektliste, technische Konfigurationsnachweise. +- **Vorlage:** R06 +- **Ressourcen:** ISB + IT, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.4-S2 — [SOLL] +**Anforderung:** Sensibilisierung der Beschäftigten. +- **Organisatorisch:** Spezifisches Awareness-Modul zu Risiken des mobilen Arbeitens einbinden. +- **Technisch:** Modul im LMS bereitstellen und Teilnahme nachhalten. +- **Typische Nachweise:** Schulungsinhalt „Mobiles Arbeiten", Teilnahmenachweise. +- **Vorlage:** R06; VA-12 +- **Ressourcen:** ISB, gering. +- **AL-Filter:** AL2, AL3 + +### 2.1.4-H1 — [HOCH] +**Anforderung:** Schutzmaßnahmen gegen Abhören und Einsehen sind umgesetzt. (C) +- **Organisatorisch:** Vorgaben für vertrauliche Umgebungen (keine Bearbeitung sensibler Daten in öffentlichen Bereichen, diskrete Gesprächsführung) verbindlich regeln. +- **Technisch:** Blickschutzfilter, automatische Sperre bei Inaktivität, Verzicht auf ungesicherte WLANs; verschlüsselte Kommunikation (BL-EUC-02 Sichtschutz/Session-Lock). +- **Typische Nachweise:** Ausgabe/Nachweis Blickschutzfilter, Richtlinienregelung, Konfiguration Bildschirmsperre. +- **Vorlage:** R06 +- **Ressourcen:** IT, gering; Beschaffung Blickschutzfilter — führt zu Aufgabe. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 3.1.1 — Sicherheitszonen und Zutrittsschutz + +### 3.1.1-M1 — [MUSS] +**Anforderung:** Ein Sicherheitszonenkonzept einschließlich zugehöriger Schutzmaßnahmen auf Basis der Anforderungen an die Handhabung von Informationswerten ist vorhanden. +- **Organisatorisch:** Zonenmodell (z. B. öffentlich, intern, geschützt, hochsicher) mit Schutzanforderungen je Zone definieren und Standorte/Räume zuordnen. +- **Technisch:** Zutrittskontrollsystem, Zonenpläne und bauliche/technische Maßnahmen (Türen, Schließanlage, Einbruchmeldeanlage) je Zone abbilden (BL-PHY-01 Zonenmodell). +- **Typische Nachweise:** Sicherheitszonenkonzept, Zonen-/Raumplan, Maßnahmenzuordnung je Zone. +- **Vorlage:** R07 +- **Ressourcen:** ISB + Facility, mittel; bauliche Maßnahmen ggf. investiv — führt zu Aufgabe. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-M2 — [MUSS] +**Anforderung:** Die definierten Schutzmaßnahmen sind umgesetzt. +- **Organisatorisch:** Umsetzungsstand je Zone/Standort prüfen und Restmaßnahmen nachverfolgen. +- **Technisch:** Zutrittskontrolle, Schließanlage, EMA/Videoüberwachung gemäß Konzept in Betrieb; Wirksamkeit prüfen. +- **Typische Nachweise:** Umsetzungsnachweise (Fotos, Abnahmen), Konfiguration Zutrittskontrolle, Begehungsprotokoll. +- **Vorlage:** R07 +- **Ressourcen:** Facility + IT, mittel. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-M3 — [MUSS] +**Anforderung:** Der Verhaltenskodex für Sicherheitszonen ist allen beteiligten Personen bekannt. +- **Organisatorisch:** Verhaltensregeln je Zone (Zutritt, Begleitung, Foto-/Geräteverbot) dokumentieren und kommunizieren; Aushänge an Zonenübergängen. +- **Technisch:** Kodex im Intranet bereitstellen; Kenntnisnahme über Portal erfassen. +- **Typische Nachweise:** Verhaltenskodex, Aushänge, Kenntnisnahmen. +- **Vorlage:** R07 +- **Ressourcen:** ISB + Facility, gering. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-S1 — [SOLL] +**Anforderung:** Verfahren für die Vergabe und den Entzug von Zutrittsrechten sind etabliert. +- **Organisatorisch:** Antrags-, Genehmigungs- und Entzugsprozess für Zutrittsrechte (inkl. Deprovisionierung bei Austritt) definieren. +- **Technisch:** Zutrittsrechte im Zutrittskontrollsystem rollenbasiert vergeben; Entzug an HR-Austrittsprozess koppeln (BL-PHY-02 Zutrittsberechtigungen). +- **Typische Nachweise:** Verfahrensbeschreibung, Zutrittsrechteanträge, Berechtigungsliste. +- **Vorlage:** R07; VA-17 +- **Ressourcen:** Facility + HR, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-S2 — [SOLL] +**Anforderung:** Richtlinien für das Besuchermanagement (Registrierung, Begleitung) sind definiert. +- **Organisatorisch:** Besucherrichtlinie mit Anmeldung, Ausweispflicht, Begleitung und Belehrung festlegen. +- **Technisch:** Besuchermanagement-System/Besucherbuch mit Ein-/Ausgangserfassung und Badge-Vergabe. +- **Typische Nachweise:** Besucherrichtlinie, Besucherprotokolle, Besucherausweise. +- **Vorlage:** R07; VA-17 +- **Ressourcen:** Empfang/Facility, gering. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-S3 — [SOLL] +**Anforderung:** Richtlinien für das Mitführen und Nutzen mobiler IT-Geräte und Datenträger sind definiert und umgesetzt. +- **Organisatorisch:** Regeln zu Registrierung, Kennzeichnung und Nutzung mitgeführter Geräte/Datenträger in sensiblen Zonen festlegen. +- **Technisch:** Kennzeichnungs-/Registrierungssystem; ggf. technische Sperren (Portkontrolle) in Hochsicherheitszonen. +- **Typische Nachweise:** Richtlinie, Geräteregister, Kennzeichnungsnachweise. +- **Vorlage:** R07; VA-17 +- **Ressourcen:** ISB + Facility, gering. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-S4 — [SOLL] +**Anforderung:** Netzwerk-/Infrastrukturkomponenten (eigene oder Kundennetze) sind gegen unbefugten Zugriff geschützt. +- **Organisatorisch:** Verantwortlichkeiten und Zutrittsregeln für Technik-/Verteilerräume festlegen. +- **Technisch:** Verschließbare Verteiler/Serverräume, Zutrittsprotokollierung, physische Sicherung von Netzkomponenten (BL-PHY-03 Technikräume). +- **Typische Nachweise:** Zutrittsprotokolle Technikräume, Fotonachweis Absicherung, Schließplan. +- **Vorlage:** R07; VA-17 +- **Ressourcen:** Facility + IT, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-S5 — [SOLL] +**Anforderung:** Externe Liegenschaften zur Speicherung/Verarbeitung von Informationswerten sind im Zonenkonzept berücksichtigt. +- **Organisatorisch:** Externe Standorte (Lager, Werkstätten, Teststrecken, RZ) erfassen und ins Zonenkonzept einordnen; vertragliche Sicherheitsanforderungen prüfen. +- **Technisch:** Zonen-/Schutzanforderungen auf externe Liegenschaften übertragen und deren Umsetzung nachweisen. +- **Typische Nachweise:** Liste externer Liegenschaften, Zonen-Zuordnung, Nachweise externer Schutzmaßnahmen. +- **Vorlage:** R07; VA-17 +- **Ressourcen:** ISB + Facility, gering. +- **AL-Filter:** AL2, AL3 + +### 3.1.1-H1 — [HOCH] +**Anforderung:** Schutzmaßnahmen gegen einfaches Abhören und Einsehen sind umgesetzt. (C) +- **Organisatorisch:** Sensible Besprechungs-/Arbeitsräume ausweisen und Nutzungsregeln (kein Einsehen von außen, keine unbefugten Aufzeichnungen) festlegen. +- **Technisch:** Sichtschutz (Folien/Jalousien), Schallschutz, ggf. Abschirmung; kontrollierter Zutritt zu sensiblen Räumen (BL-PHY-04 Abhör-/Sichtschutz). +- **Typische Nachweise:** Raumkonzept sensibler Räume, Nachweis Sicht-/Schallschutzmaßnahmen. +- **Vorlage:** R07 +- **Ressourcen:** Facility, mittel; bauliche Maßnahmen ggf. investiv — führt zu Aufgabe. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 3.1.4 — Mobile IT-Geräte und Datenträger + +### 3.1.4-M1 — [MUSS] +**Anforderung:** Die Anforderungen an mobile IT-Geräte und mobile Datenträger sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +- **Organisatorisch:** Richtlinie zu mobilen Geräten/Datenträgern (zugelassene Geräte, Nutzung, Aufbewahrung, Verlust-Meldung, Rückgabe) festlegen. +- **Technisch:** Zentrale Verwaltung über MDM/UEM mit erzwungenen Sicherheitsprofilen; Kontrolle des Wechseldatenträgereinsatzes (BL-EUC-01 Endgeräteschutz). +- **Typische Nachweise:** Richtlinie mobile Geräte/Datenträger, MDM-Richtlinien, Kenntnisnahmen. +- **Vorlage:** R06 +- **Ressourcen:** IT + ISB, mittel; MDM/UEM ggf. zu beschaffen/ausbauen — führt zu Aufgabe. +- **AL-Filter:** AL2, AL3 + +### 3.1.4-S1 — [SOLL] +**Anforderung:** Registrierung der IT-Geräte. +- **Organisatorisch:** Verbindliche Registrierung mobiler Geräte im Bestand (Zuordnung Nutzer/Gerät) vor Ausgabe. +- **Technisch:** Inventarisierung über MDM/CMDB mit eindeutiger Geräte-ID und Statuspflege. +- **Typische Nachweise:** Geräteinventar/CMDB-Auszug, Übergabeprotokolle. +- **Vorlage:** R06 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 3.1.4-H1 — [HOCH] +**Anforderung:** Generelle Verschlüsselung mobiler Datenträger bzw. der gespeicherten Informationswerte; wo technisch nicht machbar, gleichwertige Maßnahmen. (C, I) +- **Organisatorisch:** Verschlüsselungspflicht für mobile Geräte/Datenträger verbindlich festlegen; Ausnahmen mit gleichwertigen Ersatzmaßnahmen dokumentieren. +- **Technisch:** Full-Disk-Encryption (z. B. BitLocker/FileVault) und Verschlüsselung von Wechseldatenträgern per MDM erzwingen; zentrales Schlüssel-/Recovery-Management (BL-CRY-02 Datenträgerverschlüsselung). +- **Typische Nachweise:** Verschlüsselungsrichtlinie, MDM-Compliance-Report (Encryption-Status), Ausnahmedokumentation. +- **Vorlage:** R06 +- **Ressourcen:** IT, gering–mittel; über MDM steuerbar. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 4.1.1 — Identifikationsmittel + +### 4.1.1-M1 — [MUSS] +**Anforderung:** Die Anforderungen an den Umgang mit Identifikationsmitteln über den gesamten Lebenszyklus sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +- **Organisatorisch:** Lebenszyklus von Identifikationsmitteln (Ausweise, Token, Schlüssel, Zertifikate) von Ausgabe über Nutzung bis Rückgabe/Sperrung regeln; Verantwortlichkeiten festlegen. +- **Technisch:** Zentrale Verwaltung von Ausweisen/Token/Zertifikaten mit Statusführung; Kopplung an Zutritts-/IAM-System (BL-IAM-06 Identifikationsmittel). +- **Typische Nachweise:** Richtlinie/Verfahren Identifikationsmittel, Ausgabe-/Rückgabeprotokolle, Bestandsführung. +- **Vorlage:** R08 +- **Ressourcen:** IT + Facility, mittel. +- **AL-Filter:** AL2, AL3 + +### 4.1.1-S1 — [SOLL] +**Anforderung:** Identifikationsmittel können nur unter kontrollierten Bedingungen erstellt werden. +- **Organisatorisch:** Erstellung von Ausweisen/Token an autorisierte Stellen und dokumentierte Freigaben binden (Vier-Augen-Prinzip bei sensiblen Mitteln). +- **Technisch:** Zugriff auf Ausweisdrucker/Token-Personalisierung und Zertifikats-CA beschränken und protokollieren (BL-IAM-06). +- **Typische Nachweise:** Berechtigungsnachweis Erstellungssysteme, Erstellungsprotokolle, Freigaben. +- **Vorlage:** R08; VA-03 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.1-H1 — [HOCH] +**Anforderung:** Eine Strategie zur Sperrung oder Ungültigmachung von Identifikationsmitteln im Verlustfall ist vorbereitet und soweit möglich umgesetzt. (C, I, A) +- **Organisatorisch:** Verlust-/Sperrprozess mit definierten Meldewegen und Reaktionszeiten festlegen; Verantwortliche und Erreichbarkeit (auch außerhalb Geschäftszeiten) benennen. +- **Technisch:** Sofortige Sperrung von Ausweisen/Token im Zutritts-/IAM-System, Zertifikatssperrung (CRL/OCSP); Remote-Wipe für Geräte-gebundene Mittel (BL-IAM-06). +- **Typische Nachweise:** Sperrprozess-Beschreibung, dokumentierte Sperrvorgänge, CRL-/Sperrnachweise. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering–mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 4.1.2 — Benutzerauthentifizierung + +### 4.1.2-M1 — [MUSS] +**Anforderung:** Die Verfahren zur Benutzerauthentifizierung sind auf Basis einer Risikobewertung ausgewählt; mögliche Angriffsszenarien wurden berücksichtigt. +- **Organisatorisch:** Authentifizierungsverfahren je System risikobasiert festlegen (Internet-Exponiertheit, Schutzbedarf); Auswahl dokumentieren. +- **Technisch:** Risikoabhängige Zuordnung von Verfahren (Passwort, MFA, zertifikatsbasiert) in der IAM-Architektur; besonders für extern erreichbare Dienste MFA vorsehen (BL-IAM-02 MFA). +- **Typische Nachweise:** Risikobewertung Authentifizierung, Zuordnung Verfahren je System. +- **Vorlage:** R08; VA-09 +- **Ressourcen:** ISB + IT, mittel. +- **AL-Filter:** AL2, AL3 + +### 4.1.2-M2 — [MUSS] +**Anforderung:** Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt. +- **Organisatorisch:** Mindeststandards für Authentifizierung (starke Passwörter, MFA für kritische/exponierte Zugänge) verbindlich vorgeben. +- **Technisch:** Zentrale Authentifizierung (IdP/SSO) mit MFA; Passwortrichtlinie technisch erzwingen (BL-IAM-01 Passwort, BL-IAM-02 MFA). +- **Typische Nachweise:** IdP-/MFA-Konfiguration, Passwortrichtlinien-Konfiguration, Systemübersicht mit Verfahren. +- **Vorlage:** R08 +- **Ressourcen:** IT, mittel; MFA-Ausbau ggf. — führt zu Aufgabe. +- **AL-Filter:** AL2, AL3 + +### 4.1.2-S1 — [SOLL] +**Anforderung:** Die Authentifizierungsverfahren sind auf Basis der geschäftlichen und sicherheitsrelevanten Anforderungen definiert und umgesetzt. +- **Organisatorisch:** Anforderungen aus Fachbereichen und Sicherheit je Anwendung abstimmen und Zielverfahren festlegen. +- **Technisch:** Verfahren im IdP/Anwendungsstack konfigurieren und rollout-seitig durchsetzen. +- **Typische Nachweise:** Konzept Authentifizierungsverfahren, Konfigurationsnachweise. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 4.1.2-S2 — [SOLL] +**Anforderung:** Benutzer werden mindestens durch starke Passwörter nach bewährten und anerkannten Praktiken authentifiziert. +- **Organisatorisch:** Passwortrichtlinie (Länge, Komplexität/Passphrasen, Sperrung kompromittierter Passwörter) gemäß anerkannter Praxis festlegen. +- **Technisch:** Richtlinie zentral erzwingen (Directory/IdP), Sperrlisten für kompromittierte Passwörter, keine erzwungenen periodischen Wechsel ohne Anlass (BL-IAM-01 Passwort). +- **Typische Nachweise:** Passwortrichtlinie, Directory-/IdP-Konfiguration. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.2-S3 — [SOLL] +**Anforderung:** Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt (z. B. PAM, Zwei-Faktor-Authentifizierung). +- **Organisatorisch:** MFA-Pflicht und PAM-Nutzung für administrative/privilegierte Konten festlegen. +- **Technisch:** Privileged-Access-Management mit Session-Kontrolle und obligatorischer MFA für Admin-Zugänge (BL-IAM-05 Privileged Access). +- **Typische Nachweise:** PAM-Konfiguration, MFA-Nachweis Admin-Konten, Liste privilegierter Konten. +- **Vorlage:** R08 +- **Ressourcen:** IT, mittel; PAM ggf. zu beschaffen — führt zu Aufgabe. +- **AL-Filter:** AL2, AL3 + +### 4.1.2-H1 — [HOCH] +**Anforderung:** Authentifizierung und Zugangskontrolle sind durch ergänzende Maßnahmen verstärkt (z. B. Zugriffsüberwachung, starke Authentifizierung, automatische Abmeldung, Sperre bei Inaktivität, Brute-Force-Prävention). (C, I, A) +- **Organisatorisch:** Risikobasiert ergänzende Schutzmaßnahmen je System festlegen und deren Wirksamkeit prüfen. +- **Technisch:** Account-Lockout/Brute-Force-Schutz, Session-Timeout und automatische Abmeldung, kontinuierliches Zugriffs-/Anomaliemonitoring (SIEM) (BL-IAM-02, BL-IAM-05). +- **Typische Nachweise:** Konfiguration Lockout/Session-Timeout, Monitoring-/SIEM-Nachweise. +- **Vorlage:** R08 +- **Ressourcen:** IT, mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 4.1.2-V1 — [SEHR HOCH] +**Anforderung:** Vor dem Zugriff auf Daten mit sehr hohem Schutzbedarf werden Benutzer mittels starker Authentifizierung (z. B. Zwei-Faktor) nach dem Stand der Technik authentifiziert. (C, I) +- **Organisatorisch:** Für Zugriffe auf sehr hoch schutzbedürftige Daten verbindliche Starke-Authentifizierung-Pflicht festlegen. +- **Technisch:** Phishing-resistente MFA (z. B. FIDO2/Zertifikate) für den Zugang zu sehr hoch klassifizierten Daten erzwingen (BL-IAM-02 MFA). +- **Typische Nachweise:** MFA-Enforcement-Konfiguration für Zielsysteme, Zugriffsprotokolle. +- **Vorlage:** R08 +- **Ressourcen:** IT, mittel. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 4.1.3 — Benutzerkonten + +### 4.1.3-M1 — [MUSS] +**Anforderung:** Das Erstellen, Ändern und Löschen von Benutzerkonten wird durchgeführt. +- **Organisatorisch:** Joiner-Mover-Leaver-Prozess mit Verantwortlichkeiten und Auslösern (HR-Events) definieren. +- **Technisch:** Kontenlebenszyklus über IAM/Provisioning möglichst automatisiert an HR-System koppeln (BL-IAM-03 Kontenlebenszyklus). +- **Typische Nachweise:** Prozessbeschreibung JML, Provisioning-Logs, Beispiel-Tickets. +- **Vorlage:** R08; VA-03 +- **Ressourcen:** IT + HR, mittel. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-M2 — [MUSS] +**Anforderung:** Eindeutige und personalisierte Benutzerkonten werden verwendet. +- **Organisatorisch:** Grundsatz personalisierter Konten festlegen; Ausnahmen (Sammelkonten) nur geregelt zulassen. +- **Technisch:** Eindeutige Namenskonvention und ID-Vergabe im Directory; keine geteilten personenbezogenen Logins. +- **Typische Nachweise:** Namenskonvention, Kontenauswertung Directory. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-M3 — [MUSS] +**Anforderung:** Die Nutzung von Sammelkonten ist geregelt (z. B. beschränkt auf Fälle, in denen Nachvollziehbarkeit verzichtbar ist). +- **Organisatorisch:** Zulässige Anwendungsfälle, Genehmigung und Verantwortliche für Sammelkonten dokumentieren. +- **Technisch:** Sammelkonten inventarisieren, Zugriff einschränken und, wo möglich, ergänzend protokollieren. +- **Typische Nachweise:** Regelung Sammelkonten, Liste genehmigter Sammelkonten. +- **Vorlage:** R08 +- **Ressourcen:** IT + ISB, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-M4 — [MUSS] +**Anforderung:** Benutzerkonten werden unmittelbar nach dem Ausscheiden des Nutzers deaktiviert (z. B. bei Vertragsende). +- **Organisatorisch:** Austrittsprozess mit sofortiger Kontensperrung und definierter Frist verbindlich festlegen. +- **Technisch:** Automatische Deaktivierung durch HR-getriggertes Deprovisioning im IAM (BL-IAM-03 Kontenlebenszyklus). +- **Typische Nachweise:** Deaktivierungsnachweise, Austritts-/Deprovisioning-Logs, Fristdefinition. +- **Vorlage:** R08 +- **Ressourcen:** IT + HR, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-M5 — [MUSS] +**Anforderung:** Benutzerkonten werden regelmäßig überprüft. +- **Organisatorisch:** Turnus für Kontenreviews (Rezertifizierung) mit Verantwortlichen festlegen. +- **Technisch:** Reports über aktive/inaktive/verwaiste Konten aus IAM/Directory; ggf. Recertification-Workflow (BL-IAM-03). +- **Typische Nachweise:** Review-Protokolle, Reports verwaister Konten, Rezertifizierungsnachweise. +- **Vorlage:** R08 +- **Ressourcen:** IT + Fachbereiche, gering–mittel; wiederkehrend. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-M6 — [MUSS] +**Anforderung:** Die Anmeldeinformationen werden dem Nutzer auf sichere Weise bereitgestellt. +- **Organisatorisch:** Sicheren Übergabeprozess für Erstzugangsdaten definieren (getrennte Kanäle, erzwungener Wechsel bei Erstanmeldung). +- **Technisch:** Initialpasswörter über sichere Kanäle, Einmalpasswörter/Aktivierungslinks, erzwungener Passwortwechsel bei Erstanmeldung (BL-IAM-01 Passwort). +- **Typische Nachweise:** Prozessbeschreibung Erstzugang, Konfiguration erzwungener Wechsel. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-M7 — [MUSS] +**Anforderung:** Eine Richtlinie zum Umgang mit Anmeldeinformationen ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt. +- **Organisatorisch:** Richtlinie zum Umgang mit Credentials (Geheimhaltung, keine Weitergabe, Umgang bei Verdacht auf Kompromittierung) erstellen und kommunizieren. +- **Technisch:** Bereitstellung eines Passwort-Managers, Vorgaben zu Speicherung/Nutzung technisch unterstützen (BL-IAM-01). +- **Typische Nachweise:** Credential-Richtlinie, Kenntnisnahmen, Bereitstellung Passwort-Manager. +- **Vorlage:** R08 +- **Ressourcen:** ISB + IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S1 — [SOLL] +**Anforderung:** Ein Basiskonto mit minimalen Zugriffsrechten und Funktionalitäten existiert und wird genutzt. +- **Organisatorisch:** Standard-/Basisprofil mit Minimalrechten als Ausgangsbasis für neue Konten festlegen. +- **Technisch:** Standardrolle mit minimalen Rechten im IAM als Default zuweisen (Least Privilege, BL-IAM-04 Rollenmodell). +- **Typische Nachweise:** Definition Basiskonto/-rolle, Rollenzuordnung im IAM. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S2 — [SOLL] +**Anforderung:** Vom Hersteller vorkonfigurierte Standardkonten und -passwörter sind deaktiviert (z. B. Sperren oder Passwortänderung). +- **Organisatorisch:** Hardening-Vorgabe zum Umgang mit Default-Konten bei Inbetriebnahme festlegen. +- **Technisch:** Default-Accounts deaktivieren/umbenennen und Default-Passwörter ändern; über Hardening-Baseline prüfen (BL-OPS-01 Hardening). +- **Typische Nachweise:** Hardening-Checkliste, Nachweis deaktivierter Default-Konten. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S3 — [SOLL] +**Anforderung:** Benutzerkonten werden durch die verantwortliche Stelle erstellt oder autorisiert. +- **Organisatorisch:** Zuständige Stelle für Kontenerstellung/-autorisierung benennen. +- **Technisch:** Kontenerstellung an autorisierte Rollen im IAM binden und protokollieren. +- **Typische Nachweise:** Rollen-/Verantwortlichkeitsdefinition, Erstellungsprotokolle. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S4 — [SOLL] +**Anforderung:** Das Erstellen von Benutzerkonten unterliegt einem Genehmigungsprozess (Vier-Augen-Prinzip). +- **Organisatorisch:** Genehmigungspflicht mit Vier-Augen-Prinzip für Kontenerstellung festlegen. +- **Technisch:** Approval-Workflow im IAM/ITSM mit dokumentierter Freigabe. +- **Typische Nachweise:** Workflow-Konfiguration, Genehmigungsnachweise/Tickets. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S5 — [SOLL] +**Anforderung:** Benutzerkonten von Dienstleistern werden nach Abschluss ihrer Aufgabe deaktiviert. +- **Organisatorisch:** Befristung und Verantwortliche für Dienstleisterkonten festlegen; Ende an Auftrags-/Vertragsende koppeln. +- **Technisch:** Ablaufdatum (Account-Expiry) für externe Konten im IAM setzen und überwachen (BL-IAM-03). +- **Typische Nachweise:** Liste Dienstleisterkonten mit Ablaufdatum, Deaktivierungsnachweise. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S6 — [SOLL] +**Anforderung:** Fristen für das Deaktivieren und Löschen von Benutzerkonten sind definiert. +- **Organisatorisch:** Fristen für Deaktivierung und endgültige Löschung (unter Beachtung von Aufbewahrungspflichten) definieren. +- **Technisch:** Fristen im IAM/Prozess automatisiert überwachen und umsetzen. +- **Typische Nachweise:** Fristenregelung, Nachweis fristgerechter Löschungen. +- **Vorlage:** R08 +- **Ressourcen:** IT + ISB, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S7 — [SOLL] +**Anforderung:** Die Verwendung von Standardpasswörtern wird technisch verhindert. +- **Organisatorisch:** Vorgabe, dass Default-/triviale Passwörter unzulässig sind. +- **Technisch:** Erzwungener Wechsel bei Erstanmeldung, Sperrlisten trivialer Passwörter im IdP (BL-IAM-01). +- **Typische Nachweise:** IdP-Konfiguration (Sperrliste, Erstwechsel). +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S8 — [SOLL] +**Anforderung:** Bei starker Authentifizierung ist die Nutzung des Mediums (z. B. Besitzfaktor) sicher. +- **Organisatorisch:** Regeln zur Ausgabe, Nutzung und Rückgabe von Token/Besitzfaktoren festlegen. +- **Technisch:** Sichere Token (Hardware-/FIDO2), PIN-Schutz und sichere Registrierung/Sperrung (BL-IAM-02 MFA). +- **Typische Nachweise:** Token-Ausgaberegelung, Konfiguration MFA-Registrierung/Sperrung. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S9 — [SOLL] +**Anforderung:** Benutzerkonten werden regelmäßig überprüft; dies umfasst auch Konten in IT-Systemen von Kunden. +- **Organisatorisch:** Kontenreviews auf Kundensysteme ausdehnen; Verantwortliche und Turnus je Kundenkontext festlegen. +- **Technisch:** Kontenlisten aus Kundensystemen periodisch abgleichen und rezertifizieren. +- **Typische Nachweise:** Review-Protokolle inkl. Kundensysteme, Rezertifizierungsnachweise. +- **Vorlage:** R08 +- **Ressourcen:** IT + Fachbereiche, mittel; wiederkehrend. +- **AL-Filter:** AL2, AL3 + +### 4.1.3-S10 — [SOLL] +**Anforderung:** Interaktive Anmeldung für Dienstkonten (technische Konten) wird technisch verhindert. +- **Organisatorisch:** Grundsatz „keine interaktive Anmeldung für Servicekonten" festlegen und Servicekonten inventarisieren. +- **Technisch:** Interaktive Logins per Richtlinie (z. B. Deny-Logon-Policy) unterbinden; Servicekonten mit minimalen Rechten und Managed/gMSA nutzen (BL-IAM-04). +- **Typische Nachweise:** Servicekonten-Inventar, Richtlinienkonfiguration (Deny interactive logon). +- **Vorlage:** R08 +- **Ressourcen:** IT, gering. +- **AL-Filter:** AL2, AL3 + +## Control 4.2.1 — Verwaltung von Zugriffsrechten + +### 4.2.1-M1 — [MUSS] +**Anforderung:** Die Anforderungen an die Verwaltung von Zugriffsrechten (Autorisierung) sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +- **Organisatorisch:** Berechtigungskonzept mit Antrags-, Genehmigungs-, Änderungs- und Entzugsprozess sowie Least-Privilege-Grundsatz definieren. +- **Technisch:** Zentrale Rechteverwaltung über IAM; rollenbasierte Vergabe und Nachverfolgbarkeit (BL-IAM-04 Rollenmodell). +- **Typische Nachweise:** Berechtigungskonzept, Antrags-/Genehmigungsnachweise, Rechteübersicht. +- **Vorlage:** R08; VA-03 +- **Ressourcen:** ISB + IT, mittel. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-M2 — [MUSS] +**Anforderung:** Die für normale, privilegierte und technische Konten vergebenen Zugriffsrechte werden regelmäßig überprüft, auch in IT-Systemen von Kunden. +- **Organisatorisch:** Rezertifizierung der Zugriffsrechte in festem Turnus mit Fachverantwortlichen; Kundensysteme einschließen. +- **Technisch:** Access-Recertification-Workflow im IAM mit Reports je Kontotyp (BL-IAM-04, BL-IAM-05 Privileged Access). +- **Typische Nachweise:** Rezertifizierungsprotokolle, Rechte-Reports (inkl. privilegiert/technisch/Kunde). +- **Vorlage:** R08; VA-03 +- **Ressourcen:** IT + Fachbereiche, mittel; wiederkehrend. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-S1 — [SOLL] +**Anforderung:** Strategien zur Autorisierung von Zugriffen auf Informationen sind vorbereitet. +- **Organisatorisch:** Autorisierungsstrategie (z. B. RBAC, Need-to-know, Datenklassifizierung als Grundlage) dokumentieren. +- **Technisch:** Strategie in IAM-Rollen-/Policy-Modell überführen. +- **Typische Nachweise:** Autorisierungsstrategie/-konzept. +- **Vorlage:** R08; VA-03 +- **Ressourcen:** ISB + IT, gering. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-S2 — [SOLL] +**Anforderung:** Autorisierungsrollen werden verwendet. +- **Organisatorisch:** Rollenmodell mit definierten Berechtigungsbündeln je Funktion etablieren und pflegen. +- **Technisch:** RBAC im IAM abbilden; Rollen zentral verwalten und zuweisen (BL-IAM-04). +- **Typische Nachweise:** Rollenkatalog, Rollen-Rechte-Matrix. +- **Vorlage:** R08 +- **Ressourcen:** IT, mittel. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-S3 — [SOLL] +**Anforderung:** Rechte werden nach dem Need-to-use-Prinzip und gemäß Rolle und/oder Verantwortungsbereich vergeben. +- **Organisatorisch:** Vergabe strikt am tatsächlichen Bedarf und an der Rolle ausrichten; Sammelberechtigungen vermeiden. +- **Technisch:** Least-Privilege-Rollen im IAM; regelmäßige Bereinigung überschüssiger Rechte. +- **Typische Nachweise:** Rechtevergabe-Nachweise, Bereinigungsprotokolle. +- **Vorlage:** R08 +- **Ressourcen:** IT, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-S4 — [SOLL] +**Anforderung:** Normale Benutzerkonten erhalten keine privilegierten Zugriffsrechte. +- **Organisatorisch:** Trennung von Standard- und Administrationskonten verbindlich vorschreiben. +- **Technisch:** Getrennte Admin-Konten, Entzug lokaler Adminrechte auf Endgeräten, Just-in-Time-Admin über PAM (BL-IAM-05). +- **Typische Nachweise:** Nachweis getrennter Admin-Konten, Auswertung lokaler Adminrechte. +- **Vorlage:** R08 +- **Ressourcen:** IT, mittel. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-S5 — [SOLL] +**Anforderung:** Die Zugriffsrechte des Nutzers werden nach Änderung seiner Verantwortlichkeiten aktualisiert. +- **Organisatorisch:** Mover-Prozess mit Neubewertung und Entzug nicht mehr benötigter Rechte bei Rollenwechsel definieren. +- **Technisch:** HR-getriggerte Rechteanpassung im IAM; Entzug alter Rollen (BL-IAM-03, BL-IAM-04). +- **Typische Nachweise:** Mover-Prozessbeschreibung, Änderungsnachweise Rechte. +- **Vorlage:** R08 +- **Ressourcen:** IT + HR, gering–mittel. +- **AL-Filter:** AL2, AL3 + +### 4.2.1-H1 — [HOCH] +**Anforderung:** Die Zugriffsrechte werden durch den verantwortlichen internen Information Officer genehmigt. (C, I, A) +- **Organisatorisch:** Genehmigung sensibler Zugriffsrechte durch den zuständigen Informationsverantwortlichen (Dateneigentümer) verbindlich festlegen. +- **Technisch:** Approval-Workflow mit Owner-Freigabe im IAM/ITSM; Genehmigungen revisionssicher protokollieren. +- **Typische Nachweise:** Freigabe-Workflow-Konfiguration, dokumentierte Owner-Genehmigungen. +- **Vorlage:** R08 +- **Ressourcen:** IT + Fachbereiche, gering–mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 4.2.1-V1 — [SEHR HOCH] +**Anforderung:** Informationen werden auf Inhaltsebene (z. B. Dateiebene) verschlüsselt gespeichert, um unbefugten Zugriff (auch privilegierter Nutzer) zu verhindern; wo nicht machbar, gleichwertige Maßnahmen. (C) +- **Organisatorisch:** Für sehr hoch schutzbedürftige Daten Inhalts-/Dateiverschlüsselung mit strikter Schlüsseltrennung von Administratoren vorschreiben; Ausnahmen mit Ersatzmaßnahmen dokumentieren. +- **Technisch:** Datei-/Feldverschlüsselung mit nutzer-/gruppenbezogenem Schlüsselmanagement, sodass privilegierte Nutzer ohne Schlüssel keinen Klartextzugriff haben (BL-CRY-01 Inhaltsverschlüsselung). +- **Typische Nachweise:** Verschlüsselungskonzept, Nachweis Datei-/Inhaltsverschlüsselung, Schlüsselmanagement-Dokumentation. +- **Vorlage:** R08 +- **Ressourcen:** IT + ISB, hoch; Verschlüsselungslösung/Key-Management ggf. zu beschaffen — führt zu Aufgabe. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +### 4.2.1-V2 — [SEHR HOCH] +**Anforderung:** Bestehende Zugriffsrechte werden in kürzeren Abständen (z. B. quartalsweise) überprüft. (C) +- **Organisatorisch:** Verkürzten Rezertifizierungsturnus (z. B. quartalsweise) für sehr hoch schutzbedürftige Bereiche festlegen. +- **Technisch:** Häufigere, automatisierte Recertification-Kampagnen im IAM mit Reporting (BL-IAM-04). +- **Typische Nachweise:** Quartalsweise Rezertifizierungsprotokolle, IAM-Kampagnenauswertung. +- **Vorlage:** R08 +- **Ressourcen:** IT + Fachbereiche, mittel; wiederkehrend. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + + +--- + +# Kapitel 5 — Kryptographie & Betriebssicherheit + +# C6 – Umsetzungshinweise Kapitel 5 (Betriebssicherheit, Kommunikation, Systementwicklung) + +## Control 5.1.1 — Einsatz von Kryptografie + +### 5.1.1-M1 — [MUSS] +**Anforderung:** Alle eingesetzten kryptografischen Verfahren bieten die im Anwendungsfeld erforderliche Sicherheit nach anerkanntem Industriestandard. +- **Organisatorisch:** Bestand der genutzten Krypto-Verfahren (Verschlüsselung, Signatur, Hash, Protokolle) je Anwendungsfall erheben und gegen aktuelle Empfehlungen (z. B. BSI TR-02102, NIST) abgleichen; veraltete Verfahren (z. B. TLS < 1.2, SHA-1, MD5) außer Betrieb nehmen. +- **Technisch:** Freigegebene Algorithmen und Mindestschlüssellängen zentral als Baseline vorgeben und in Systemkonfigurationen erzwingen (z. B. TLS-Policies, Cipher-Suites, Disk-Encryption). Referenz: BL-CRY-01 (zugelassene Algorithmen/Schlüssellängen), BL-CRY-02 (TLS-Mindeststandard). +- **Typische Nachweise:** Krypto-Katalog/Algorithmenliste mit Freigabestatus, Konfigurationsauszüge (z. B. TLS-Scan), Nachweis Ablösung veralteter Verfahren. +- **Vorlage:** R09; VA-07; BL-CRY-01; BL-CRY-02 +- **Ressourcen:** ISB/IT-Betrieb; ggf. TLS-/Config-Scanner (Beschaffung möglich); gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.1.1-S1 — [SOLL] +**Anforderung:** Ein Konzept für den Einsatz von Kryptografie ist definiert und umgesetzt. +- **Organisatorisch:** Kryptokonzept erstellen (Einsatzzwecke, zugelassene Verfahren, Schlüssellängen, Gültigkeitsdauern, Verantwortlichkeiten, Ausnahmeverfahren) und durch die Leitung freigeben lassen. +- **Technisch:** Konzeptvorgaben in Gerätehärtung, PKI-/Zertifikatsmanagement und Verschlüsselungsprofilen technisch verankern. Referenz: BL-CRY-01, BL-CRY-02. +- **Typische Nachweise:** Freigegebenes Kryptokonzept, Zuordnung Verfahren↔Anwendungsfall, Review-Vermerk. +- **Vorlage:** R09; VA-07; BL-CRY-01 +- **Ressourcen:** ISB + IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.1.1-H1 — [HOCH] +**Anforderung:** Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) sind bestimmt und erfüllt. (C, I) +- **Organisatorisch:** Für Daten mit hohem Schutzbedarf festlegen, dass Schlüssel unter eigener Kontrolle verbleiben (kein Zugriff des Dienstleisters); Schlüsselverwaltungsverantwortung und Rückgabe-/Löschprozesse vertraglich regeln. +- **Technisch:** Bring-Your-Own-Key/Hold-Your-Own-Key bzw. dedizierte Key-Management-Lösung oder HSM einsetzen; Schlüsseltrennung von Cloud-Anbieter-Schlüsseln. Referenz: BL-CRY-03 (Schlüsselhoheit/Key-Management). +- **Typische Nachweise:** KMS-/HSM-Konfiguration, Vertragsklausel Schlüsselhoheit, Nachweis getrennter Schlüsselverwaltung. +- **Vorlage:** R09; BL-CRY-03 +- **Ressourcen:** KMS/HSM oder BYOK-Funktion (Beschaffung/Lizenz möglich); mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 5.1.2 — Sicherheit bei der Informationsübertragung / Netzdienste + +### 5.1.2-M1 — [MUSS] +**Anforderung:** Die zur Informationsübertragung genutzten Netzdienste sind identifiziert und dokumentiert. +- **Organisatorisch:** Übersicht der Übertragungswege/Netzdienste (E-Mail, VPN, Fileshare, EDI, Webportale, Fernzugriff) erstellen und Verantwortliche zuweisen. +- **Technisch:** Netzdienste-Inventar mit Protokoll, Endpunkten und Schutzbedarf führen; regelmäßig aus Netz-/Firewall-Dokumentation aktualisieren. Referenz: BL-NET-01 (Netzdienste-/Übertragungsinventar). +- **Typische Nachweise:** Netzdienste-Verzeichnis, Datenfluss-/Übertragungsübersicht. +- **Vorlage:** R09; VA-07; BL-NET-01 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.1.2-M2 — [MUSS] +**Anforderung:** Richtlinien und Verfahren entsprechend den Klassifizierungsanforderungen für die Nutzung von Netzdiensten sind definiert und umgesetzt. +- **Organisatorisch:** Nutzungsvorgaben je Klassifizierungsstufe festlegen (welcher Dienst/Verschlüsselung für welche Informationsklasse zulässig ist) und kommunizieren. +- **Technisch:** Vorgaben durch Mail-Gateway-Regeln, erzwungene Transportverschlüsselung und Freigabelisten technisch durchsetzen. Referenz: BL-NET-01, BL-CRY-02. +- **Typische Nachweise:** Richtlinie Informationsübertragung, Gateway-/Mailflow-Regeln, Klassifizierungs-Mapping. +- **Vorlage:** R09; VA-07; BL-CRY-02 +- **Ressourcen:** ISB + IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.1.2-M3 — [MUSS] +**Anforderung:** Maßnahmen zum Schutz übertragener Inhalte gegen unbefugten Zugriff sind umgesetzt. +- **Organisatorisch:** Vorgeben, dass schützenswerte Inhalte nur verschlüsselt übertragen werden; Ausnahmen dokumentieren. +- **Technisch:** Transport-/Inhaltsverschlüsselung (TLS, S/MIME, PGP, verschlüsselte Container/Portale) einsetzen; unverschlüsselte Legacy-Protokolle sperren. Referenz: BL-CRY-02, BL-NET-03 (Fernzugriff/VPN). +- **Typische Nachweise:** TLS-/Verschlüsselungsnachweis, verschlüsselter Austauschkanal, Konfigurationsauszug. +- **Vorlage:** R09; BL-CRY-02 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.1.2-S1 — [SOLL] +**Anforderung:** Maßnahmen zur Sicherstellung korrekter Adressierung und korrekter Informationsübertragung sind umgesetzt. +- **Organisatorisch:** Prozesse gegen Fehlversand definieren (4-Augen bei sensiblen Verteilern, Pflege von Verteilerlisten, Sensibilisierung). +- **Technisch:** Maßnahmen wie Autovervollständigungs-Warnungen, Anti-Misdelivery-/DLP-Regeln, Empfängerbestätigung aktivieren. Referenz: BL-NET-01. +- **Typische Nachweise:** DLP-/Mailregeln, Schulungsnachweis, Verteilerpflege-Prozess. +- **Vorlage:** R09; VA-07 +- **Ressourcen:** IT-Betrieb; ggf. DLP-Funktion (Beschaffung möglich); gering. +- **AL-Filter:** AL2 + AL3 + +### 5.1.2-S2 — [SOLL] +**Anforderung:** Elektronischer Datenaustausch erfolgt mittels Inhalts- oder Transportverschlüsselung entsprechend der Klassifizierung. +- **Organisatorisch:** Je Klassifizierungsstufe festlegen, ob Transport- oder Inhaltsverschlüsselung erforderlich ist. +- **Technisch:** TLS-erzwungene Kanäle für interne/Standardübertragung, Inhaltsverschlüsselung (S/MIME, verschlüsselte Archive) für höhere Stufen. Referenz: BL-CRY-01, BL-CRY-02. +- **Typische Nachweise:** Verschlüsselungsmatrix je Klasse, Konfigurationsnachweis. +- **Vorlage:** R09; BL-CRY-02 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.1.2-S3 — [SOLL] +**Anforderung:** Fernzugriffsverbindungen zum Netzwerk der Organisation verfügen über angemessene Sicherheitsmerkmale. +- **Organisatorisch:** Fernzugriffsrichtlinie mit Genehmigung, Mehr-Faktor-Pflicht und Nutzungsbedingungen definieren. +- **Technisch:** VPN nach Stand der Technik mit MFA, starker Verschlüsselung, Endpoint-Prüfung und Sitzungsbegrenzung. Referenz: BL-NET-03 (Fernzugriff/VPN), BL-IAM-02 (MFA). +- **Typische Nachweise:** VPN-Konfiguration, MFA-Nachweis, Fernzugriffsrichtlinie. +- **Vorlage:** R09; BL-NET-03; BL-IAM-02 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.1.2-H1 — [HOCH] +**Anforderung:** Informationen werden verschlüsselt übertragen (mindestens Transportverschlüsselung) oder gleichwertig geschützt. (C) +- **Organisatorisch:** Verbindliche Verschlüsselungspflicht für Informationen mit hohem Schutzbedarf festschreiben; unverschlüsselte Ausnahmen nur mit dokumentierter Ersatzmaßnahme. +- **Technisch:** Transportverschlüsselung durchgängig erzwingen (TLS-Enforcement, verschlüsselte Tunnel); Fallback auf Klartext technisch verhindern. Referenz: BL-CRY-02. +- **Typische Nachweise:** TLS-Enforcement-Policy, Scan-Ergebnis ohne Klartextdienste. +- **Vorlage:** R09; BL-CRY-02 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.1.2-V1 — [SEHR HOCH] +**Anforderung:** Informationen werden inhaltsverschlüsselt übertragen. (C) +- **Organisatorisch:** Für sehr hohen Schutzbedarf Ende-zu-Ende-/Inhaltsverschlüsselung verpflichtend vorschreiben, unabhängig vom Transportweg. +- **Technisch:** Inhaltsverschlüsselung (S/MIME, PGP, verschlüsselte Container mit eigener Schlüsselhoheit) einsetzen; Schlüssel getrennt vom Transportkanal verwalten. Referenz: BL-CRY-01, BL-CRY-03. +- **Typische Nachweise:** Nachweis Ende-zu-Ende-Verschlüsselung, Schlüsselmanagement-Dokumentation. +- **Vorlage:** R09; BL-CRY-03 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 5.2.1 — Änderungsmanagement (Change Management) + +### 5.2.1-M1 — [MUSS] +**Anforderung:** Informationssicherheitsanforderungen für Änderungen an Organisation, Geschäftsprozessen und IT-Systemen sind bestimmt und erfüllt. +- **Organisatorisch:** Change-Management-Prozess etablieren, der Sicherheitsbewertung, Freigabe und Dokumentation jeder relevanten Änderung vorsieht. +- **Technisch:** Änderungen über Ticket-/Change-System mit Sicherheitsprüfung und Genehmigungs-Workflow abwickeln. Referenz: BL-OPS-01 (Change-Management). +- **Typische Nachweise:** Change-Records mit Sicherheitsbewertung, Change-Richtlinie, Freigaben. +- **Vorlage:** R10; VA-04; BL-OPS-01 +- **Ressourcen:** IT-Betrieb; ggf. Ticket-/Change-Tool (Beschaffung möglich); gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.1-S1 — [SOLL] +**Anforderung:** Ein formales Genehmigungsverfahren ist etabliert. +- **Organisatorisch:** Rollen (Antragsteller, Bewerter, Genehmiger) und Freigabekriterien definieren; ggf. Change Advisory Board. +- **Technisch:** Genehmigungs-Workflow im Change-Tool mit Pflichtfeldern und Freigabestufen abbilden. Referenz: BL-OPS-01. +- **Typische Nachweise:** Genehmigte Changes, Rollen-/Gremienbeschreibung. +- **Vorlage:** R10; VA-04; BL-OPS-01 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.1-S2 — [SOLL] +**Anforderung:** Die möglichen Auswirkungen von Änderungen auf die Informationssicherheit werden bewertet. +- **Organisatorisch:** Impact-/Risikoanalyse als Pflichtschritt im Change vorsehen (betroffene Assets, Schutzziele). +- **Technisch:** Bewertungsfelder/Checkliste im Change-Record, Verknüpfung mit Asset- und Risikoregister. Referenz: BL-OPS-01. +- **Typische Nachweise:** Impact-Analysen in Change-Records, Bewertungscheckliste. +- **Vorlage:** R10; VA-04 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.1-S3 — [SOLL] +**Anforderung:** Änderungen mit Auswirkung auf die Informationssicherheit werden geplant und getestet. +- **Organisatorisch:** Planungs- und Testschritte vor Produktivsetzung verbindlich vorschreiben. +- **Technisch:** Tests in getrennter Test-/Staging-Umgebung durchführen und dokumentieren. Referenz: BL-OPS-01, BL-OPS-02 (Umgebungstrennung). +- **Typische Nachweise:** Testprotokolle, Rollout-Plan. +- **Vorlage:** R10; VA-04; BL-OPS-02 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.1-S4 — [SOLL] +**Anforderung:** Verfahren zum Rückfall (Fallback) in Fehlerfällen werden berücksichtigt. +- **Organisatorisch:** Für jede relevante Änderung Rollback-/Fallback-Plan fordern. +- **Technisch:** Backups/Snapshots vor Change, dokumentierte Rücksetzschritte. Referenz: BL-OPS-01, BL-OPS-05 (Backup). +- **Typische Nachweise:** Rollback-Plan im Change, Snapshot-/Backup-Nachweis. +- **Vorlage:** R10; VA-04; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.1-H1 — [HOCH] +**Anforderung:** Die Einhaltung der Informationssicherheitsanforderungen wird während und nach den Änderungen überprüft. (C, I, A) +- **Organisatorisch:** Post-Implementation-Review mit Sicherheitsprüfung verbindlich etablieren. +- **Technisch:** Konfigurations-/Compliance-Checks nach dem Change (z. B. Baseline-Scan, Hardening-Verifikation) durchführen. Referenz: BL-OPS-01. +- **Typische Nachweise:** PIR-Protokolle, Post-Change-Scan-Ergebnisse. +- **Vorlage:** R10; VA-04 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 5.2.2 — Trennung von Entwicklungs-, Test- und Produktivumgebungen + +### 5.2.2-M1 — [MUSS] +**Anforderung:** Die IT-Systeme wurden einer Risikobewertung zur Notwendigkeit der Trennung in Entwicklungs-, Test- und Produktivsysteme unterzogen. +- **Organisatorisch:** Systeme identifizieren, bei denen Entwicklung/Test/Produktion getrennt werden muss, und Ergebnis dokumentieren. +- **Technisch:** Zuordnung der Systeme zu Umgebungen im Inventar; Risikobewertung mit Verfahren VA-09 verknüpfen. Referenz: BL-OPS-02 (Umgebungstrennung). +- **Typische Nachweise:** Risikobewertung Umgebungstrennung, System-/Umgebungszuordnung. +- **Vorlage:** R10; BL-OPS-02 +- **Ressourcen:** IT-Betrieb + ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.2-M2 — [MUSS] +**Anforderung:** Eine Segmentierung ist auf Basis der Ergebnisse der Risikoanalyse umgesetzt. +- **Organisatorisch:** Trennung organisatorisch absichern (getrennte Berechtigungen, kein Produktivzugriff aus Testkontext). +- **Technisch:** Umgebungen netz-/systemseitig trennen (getrennte Netzsegmente, Instanzen, Zugriffsrechte). Referenz: BL-OPS-02, BL-NET-01 (Segmentierung). +- **Typische Nachweise:** Netz-/Systemtrennungsnachweis, Berechtigungskonzept je Umgebung. +- **Vorlage:** R10; BL-OPS-02; BL-NET-01 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.2-S1 — [SOLL] +**Anforderung:** Die Anforderungen an Entwicklungs- und Testumgebungen sind bestimmt und erfüllt. +- **Organisatorisch:** Vorgaben für Dev-/Test-Umgebungen festlegen (Datenherkunft, Zugriff, Löschung, keine Produktivgeheimnisse). +- **Technisch:** Härtung der Testsysteme, anonymisierte Testdaten, getrennte Zugangsdaten. Referenz: BL-OPS-02. +- **Typische Nachweise:** Vorgaben Dev/Test, Nachweis Testdaten-Anonymisierung. +- **Vorlage:** R10; BL-OPS-02 +- **Ressourcen:** IT-Betrieb/Entwicklung; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +## Control 5.2.3 — Schutz vor Schadsoftware + +### 5.2.3-M1 — [MUSS] +**Anforderung:** Anforderungen zum Schutz vor Schadsoftware sind bestimmt. +- **Organisatorisch:** Richtlinie/Vorgaben zum Malware-Schutz für alle Systemtypen (Client, Server, mobile Geräte, OT) festlegen. +- **Technisch:** Schutzbedarf je Systemklasse bestimmen und Schutzmechanismen zuordnen. Referenz: BL-OPS-03 (Malware-Schutz). +- **Typische Nachweise:** Malware-Schutz-Vorgabe, Systemklassen-Zuordnung. +- **Vorlage:** R10; BL-OPS-03 +- **Ressourcen:** ISB + IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-M2 — [MUSS] +**Anforderung:** Technische und organisatorische Maßnahmen zum Schutz vor Schadsoftware sind definiert und umgesetzt. +- **Organisatorisch:** Kombination aus Nutzerverhalten (keine unbekannte Software, Umgang mit Anhängen) und technischen Kontrollen festlegen. +- **Technisch:** Endpoint-Protection/EDR flächendeckend, zentrale Verwaltung, Application-Control. Referenz: BL-OPS-03. +- **Typische Nachweise:** AV/EDR-Deployment-Report, Richtlinie, Konfiguration. +- **Vorlage:** R10; BL-OPS-03 +- **Ressourcen:** Endpoint-Protection/EDR (Beschaffung/Lizenz möglich); mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S1 — [SOLL] +**Anforderung:** Unnötige Netzwerkdienste sind deaktiviert. +- **Organisatorisch:** Vorgabe zur Minimierung von Diensten (Härtung) je Systemrolle. +- **Technisch:** Systemhärtung nach Baseline, nicht benötigte Dienste/Ports schließen. Referenz: BL-OPS-03, BL-NET-02 (Dienst-/Portfreigaben). +- **Typische Nachweise:** Härtungsbaseline, Port-/Dienste-Scan. +- **Vorlage:** R10; BL-NET-02 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S2 — [SOLL] +**Anforderung:** Der Zugriff auf Netzwerkdienste ist durch geeignete Schutzmaßnahmen auf das Notwendige beschränkt. +- **Organisatorisch:** Least-Privilege für Netzdienste vorgeben. +- **Technisch:** Firewall-/ACL-Regeln, Host-Firewalls, Segmentierung. Referenz: BL-NET-02, BL-NET-01. +- **Typische Nachweise:** Firewall-Regelwerk, ACL-Auszug. +- **Vorlage:** R10; BL-NET-02 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S3 — [SOLL] +**Anforderung:** Schutzsoftware gegen Schadsoftware ist installiert und wird regelmäßig automatisch aktualisiert. +- **Organisatorisch:** Aktualitäts-/Abdeckungsvorgabe für Schutzsoftware festlegen. +- **Technisch:** Automatische Signatur-/Engine-Updates, zentrales Reporting über Abdeckung und Update-Stand. Referenz: BL-OPS-03. +- **Typische Nachweise:** Update-/Abdeckungsreport, Konfiguration Auto-Update. +- **Vorlage:** R10; BL-OPS-03 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S4 — [SOLL] +**Anforderung:** Empfangene Dateien und Software werden vor Ausführung automatisch geprüft (On-Access-Scan). +- **Organisatorisch:** On-Access-Scan verbindlich vorgeben. +- **Technisch:** Echtzeitschutz/On-Access-Scanning aktivieren und gegen Deaktivierung schützen. Referenz: BL-OPS-03. +- **Typische Nachweise:** Konfigurationsnachweis Echtzeitschutz. +- **Vorlage:** R10; BL-OPS-03 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S5 — [SOLL] +**Anforderung:** Der gesamte Datenbestand aller Systeme wird regelmäßig auf Schadsoftware geprüft. +- **Organisatorisch:** Turnus für vollständige Scans festlegen. +- **Technisch:** Geplante Full-Scans zentral steuern und auswerten. Referenz: BL-OPS-03. +- **Typische Nachweise:** Scan-Zeitpläne, Scan-Berichte. +- **Vorlage:** R10; BL-OPS-03 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S6 — [SOLL] +**Anforderung:** Über zentrale Gateways übertragene Daten werden automatisch durch Schutzsoftware geprüft. +- **Organisatorisch:** Prüfung an E-Mail-/Web-/Übergabe-Gateways verpflichtend festlegen. +- **Technisch:** Gateway-Scanning (Mail-Security, Web-Proxy/Sandbox) einsetzen. Referenz: BL-OPS-03, BL-NET-02. +- **Typische Nachweise:** Gateway-Konfiguration, Scan-Statistik. +- **Vorlage:** R10; BL-OPS-03 +- **Ressourcen:** Mail-/Web-Security-Gateway (Beschaffung möglich); mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S7 — [SOLL] +**Anforderung:** Maßnahmen, die verhindern, dass Schutzsoftware durch Nutzer deaktiviert oder verändert wird, sind umgesetzt. +- **Organisatorisch:** Verbot der Deaktivierung in der Richtlinie verankern. +- **Technisch:** Tamper-Protection, Entzug lokaler Admin-Rechte, zentrale Richtlinienbindung. Referenz: BL-OPS-03, BL-IAM-05 (Privilegien). +- **Typische Nachweise:** Tamper-Protection-Konfiguration, Rechtekonzept. +- **Vorlage:** R10; BL-OPS-03; BL-IAM-05 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.3-S8 — [SOLL] +**Anforderung:** Für IT-Systeme ohne Schutzsoftware sind alternative Maßnahmen umgesetzt. +- **Organisatorisch:** Systeme ohne AV (z. B. OT, Appliances) identifizieren und Ersatzmaßnahmen festlegen. +- **Technisch:** Netzisolation, Application-Whitelisting, minimale Dienste, erhöhte Resilienz. Referenz: BL-OPS-03, BL-NET-01. +- **Typische Nachweise:** Liste betroffener Systeme mit kompensierenden Maßnahmen. +- **Vorlage:** R10; BL-NET-01 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +## Control 5.2.4 — Ereignisprotokollierung (Logging & Monitoring) + +### 5.2.4-M1 — [MUSS] +**Anforderung:** Informationssicherheitsanforderungen an den Umgang mit Ereignisprotokollen sind bestimmt und erfüllt. +- **Organisatorisch:** Logging-Konzept mit Umfang, Aufbewahrungsfristen, Zugriff, Datenschutz-/Mitbestimmungsvorgaben definieren. +- **Technisch:** Zentrale Protokollierung (SIEM/Log-Management), definierte Log-Quellen und Retention. Referenz: BL-OPS-04 (Logging/Retention). +- **Typische Nachweise:** Logging-Konzept, Aufbewahrungsvorgabe, Log-Quellenliste. +- **Vorlage:** R10; VA-13; BL-OPS-04 +- **Ressourcen:** IT-Betrieb; ggf. SIEM/Log-Management (Beschaffung möglich); mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-M2 — [MUSS] +**Anforderung:** Sicherheitsrelevante Anforderungen an die Protokollierung von Administrator- und Nutzeraktivitäten sind bestimmt und erfüllt. +- **Organisatorisch:** Festlegen, welche Admin-/Nutzeraktionen (Logins, Rechteänderungen, privilegierte Aktionen) protokolliert werden; Mitbestimmung/Datenschutz einbinden. +- **Technisch:** Audit-Logging auf Systemen und für privilegierte Zugriffe (PAM) aktivieren. Referenz: BL-OPS-04, BL-IAM-05. +- **Typische Nachweise:** Log-Auszüge Admin-Aktivitäten, Audit-Policy-Konfiguration. +- **Vorlage:** R10; VA-13; BL-OPS-04 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-M3 — [MUSS] +**Anforderung:** Die eingesetzten IT-Systeme werden hinsichtlich der Notwendigkeit der Protokollierung bewertet. +- **Organisatorisch:** Bewertungskriterien festlegen, welche Systeme protokolliert werden müssen. +- **Technisch:** Logging-Abdeckung je System dokumentieren und aus dem Asset-Inventar ableiten. Referenz: BL-OPS-04. +- **Typische Nachweise:** Bewertungsübersicht Protokollierungsbedarf. +- **Vorlage:** R10; VA-13 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-M4 — [MUSS] +**Anforderung:** Bei Nutzung externer IT-Dienste werden Informationen zu den Überwachungsmöglichkeiten eingeholt und berücksichtigt. +- **Organisatorisch:** Bei Cloud-/Dienstauswahl Logging-/Audit-Fähigkeiten abfragen und vertraglich sichern. +- **Technisch:** Verfügbare Anbieter-Logs (Audit-Logs, Access-Logs) anbinden/exportieren. Referenz: BL-OPS-04. +- **Typische Nachweise:** Anbieterauskunft Monitoring, angebundene Cloud-Logs. +- **Vorlage:** R10; VA-13 +- **Ressourcen:** IT-Betrieb/Einkauf; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-M5 — [MUSS] +**Anforderung:** Ereignisprotokolle werden regelmäßig auf Richtlinienverstöße und auffällige Probleme geprüft. +- **Organisatorisch:** Auswerteturnus und Verantwortliche festlegen; rechtliche/organisatorische Vorgaben (Datenschutz, Mitbestimmung) einhalten. +- **Technisch:** Regelbasierte Auswertung/Alerting im SIEM, Use-Cases für auffällige Ereignisse. Referenz: BL-OPS-04. +- **Typische Nachweise:** Auswerteprotokolle, SIEM-Alert-Regeln, Reports. +- **Vorlage:** R10; VA-13 +- **Ressourcen:** IT-Betrieb/Security-Analyse; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-S1 — [SOLL] +**Anforderung:** Ein Verfahren zur Eskalation relevanter Ereignisse an die verantwortliche Stelle ist definiert und etabliert. +- **Organisatorisch:** Eskalationswege und Reaktionszuständigkeiten festlegen (Anbindung an Incident-Prozess R04). +- **Technisch:** Automatisierte Alerts an definierte Empfänger/Ticketsystem. Referenz: BL-OPS-04. +- **Typische Nachweise:** Eskalationsverfahren, Alert-Routing, Ticket-Nachweise. +- **Vorlage:** R10; VA-13; VA-01 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-S2 — [SOLL] +**Anforderung:** Ereignisprotokolle sind gegen Veränderung geschützt. +- **Organisatorisch:** Vorgabe zur Integrität und Zugriffsbeschränkung der Logs. +- **Technisch:** Zentrale, schreibgeschützte/WORM-Logablage, getrennte Log-Umgebung, Zugriffskontrolle. Referenz: BL-OPS-04. +- **Typische Nachweise:** Konfiguration Log-Integritätsschutz, Zugriffskonzept Log-System. +- **Vorlage:** R10; BL-OPS-04 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-S3 — [SOLL] +**Anforderung:** Eine angemessene Überwachung und Aufzeichnung aller informationssicherheitsrelevanten Aktionen im Netzwerk ist etabliert. +- **Organisatorisch:** Umfang der Netzüberwachung festlegen. +- **Technisch:** Netzwerk-Monitoring/IDS/NDR, zentrale Aufzeichnung sicherheitsrelevanter Netzereignisse. Referenz: BL-NET-01, BL-OPS-04. +- **Typische Nachweise:** IDS/NDR-Konfiguration, Monitoring-Reports. +- **Vorlage:** R10; BL-NET-01 +- **Ressourcen:** IDS/NDR-Lösung (Beschaffung möglich); mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.4-H1 — [HOCH] +**Anforderung:** Sicherheitsrelevante Anforderungen an den Umgang mit Ereignisprotokollen (z. B. vertragliche) sind bestimmt und umgesetzt. (C, I, A) +- **Organisatorisch:** Kunden-/vertragliche Log-Anforderungen erheben und umsetzen (z. B. Aufbewahrung, Bereitstellung). +- **Technisch:** Erweiterte Retention, kundenspezifische Log-Trennung/-Bereitstellung. Referenz: BL-OPS-04. +- **Typische Nachweise:** Mapping vertragliche Anforderungen↔Umsetzung, Retention-Konfiguration. +- **Vorlage:** R10; BL-OPS-04 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.4-H2 — [HOCH] +**Anforderung:** Ereignisse zu Auf- und Abbau von Fernzugriffssitzungen werden protokolliert. (C, I, A) +- **Organisatorisch:** Protokollierungspflicht für Fernwartung/Fernzugriff festlegen. +- **Technisch:** Session-Logging in VPN/PAM/Fernwartungslösung, inkl. Start-/Endzeit und Nutzer. Referenz: BL-NET-03, BL-OPS-04. +- **Typische Nachweise:** Fernzugriffs-Session-Logs, PAM-Aufzeichnungen. +- **Vorlage:** R10; BL-NET-03 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.4-V1 — [SEHR HOCH] +**Anforderung:** Protokollierung jedes Zugriffs auf Daten mit sehr hohem Schutzbedarf, soweit technisch/rechtlich zulässig. (C, I) +- **Organisatorisch:** Zugriffsprotokollierung für sehr hohe Schutzklasse verbindlich festlegen; Datenschutz-/Mitbestimmung klären. +- **Technisch:** Objekt-/Datenzugriffs-Auditing (File-/DB-Access-Logs) für die betreffenden Datenbestände aktivieren. Referenz: BL-OPS-04. +- **Typische Nachweise:** Data-Access-Logs, Konfiguration Objekt-Auditing. +- **Vorlage:** R10; BL-OPS-04 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 5.2.5 — Umgang mit technischen Schwachstellen (Vulnerability & Patch Management) + +### 5.2.5-M1 — [MUSS] +**Anforderung:** Informationen über technische Schwachstellen der eingesetzten IT-Systeme werden erhoben. +- **Organisatorisch:** Quellen definieren (Herstellermeldungen, CVE/CERT-Feeds, Audits) und Verantwortliche für die Auswertung benennen. +- **Technisch:** Abgleich von Schwachstelleninfos mit Asset-Inventar; automatisierte Vulnerability-Feeds/Scanner. Referenz: BL-OPS-06 (Patch-/Schwachstellenmanagement). +- **Typische Nachweise:** Abonnierte Feeds/CERT-Meldungen, Schwachstellenliste, Scan-Reports. +- **Vorlage:** R10; VA-04; VA-06; BL-OPS-06 +- **Ressourcen:** IT-Betrieb; ggf. Vulnerability-Scanner (Beschaffung möglich); mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.5-M2 — [MUSS] +**Anforderung:** Potenziell betroffene IT-Systeme/Software werden identifiziert und das Risiko bewertet. +- **Organisatorisch:** Bewertungsprozess (Kritikalität, CVSS, Betroffenheit) mit Fristen etablieren. +- **Technisch:** Verknüpfung Schwachstelle↔Asset, Priorisierung nach Schweregrad/Exponiertheit. Referenz: BL-OPS-06. +- **Typische Nachweise:** Risikobewertungen je Schwachstelle, Priorisierungsliste. +- **Vorlage:** R10; VA-06; BL-OPS-06 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.5-M3 — [MUSS] +**Anforderung:** Risiken aus Schwachstellen werden behandelt. +- **Organisatorisch:** Behandlungsentscheidung (Patch, Mitigation, Akzeptanz) dokumentieren und nachverfolgen. +- **Technisch:** Umsetzung von Patches/Workarounds, Nachkontrolle. Referenz: BL-OPS-06. +- **Typische Nachweise:** Maßnahmen-/Behandlungsnachweise, Ticket-Historie. +- **Vorlage:** R10; VA-06; BL-OPS-06 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.5-S1 — [SOLL] +**Anforderung:** Ein angemessenes Patch-Management ist definiert und umgesetzt. +- **Organisatorisch:** Patch-Prozess mit Test-, Freigabe- und Fristenregelung (nach Kritikalität) festlegen. +- **Technisch:** Patch-Management-Werkzeug mit Verteilung, Test-Ring und Reporting. Referenz: BL-OPS-06. +- **Typische Nachweise:** Patch-Richtlinie, Patch-Reports/Compliance-Grad. +- **Vorlage:** R10; VA-06; BL-OPS-06 +- **Ressourcen:** Patch-Management-Tool (Beschaffung möglich); mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.5-S2 — [SOLL] +**Anforderung:** Risikominimierende Maßnahmen werden bei Bedarf umgesetzt. +- **Organisatorisch:** Für nicht sofort patchbare Schwachstellen kompensierende Maßnahmen festlegen. +- **Technisch:** Virtual Patching (IPS/WAF), Isolation, Dienstabschaltung. Referenz: BL-OPS-06, BL-NET-02. +- **Typische Nachweise:** Dokumentierte Mitigationsmaßnahmen. +- **Vorlage:** R10; BL-OPS-06 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.5-S3 — [SOLL] +**Anforderung:** Die erfolgreiche Installation von Patches wird verifiziert. +- **Organisatorisch:** Verifikationsschritt im Patch-Prozess vorsehen. +- **Technisch:** Compliance-Reports/Re-Scan zur Bestätigung des Patch-Stands. Referenz: BL-OPS-06. +- **Typische Nachweise:** Patch-Compliance-Report, Verifikations-Scan. +- **Vorlage:** R10; BL-OPS-06 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +## Control 5.2.6 — Prüfung (Audit) von IT-Systemen und -Diensten + +### 5.2.6-M1 — [MUSS] +**Anforderung:** Anforderungen an die Prüfung (Audit) von IT-Systemen oder -Diensten sind bestimmt. +- **Organisatorisch:** Prüfumfang, -kriterien und -verantwortliche festlegen (technische Systemprüfungen/Security-Tests). +- **Technisch:** Prüfmethoden je Systemklasse definieren (Konfigurationsprüfung, Schwachstellenscan). Referenz: BL-OPS-07 (Systemprüfung/Scanning). +- **Typische Nachweise:** Prüfkonzept/-vorgaben, Prüfkriterien. +- **Vorlage:** R10; VA-06; BL-OPS-07 +- **Ressourcen:** IT-Betrieb/ISB; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-M2 — [MUSS] +**Anforderung:** Der Umfang der Systemprüfung wird rechtzeitig festgelegt. +- **Organisatorisch:** Scope und Zeitpunkt vorab abstimmen und dokumentieren. +- **Technisch:** Zieldefinition (Systeme, Tiefe, Werkzeuge) vor Prüfbeginn. Referenz: BL-OPS-07. +- **Typische Nachweise:** Scope-Dokument, Prüfplan. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-M3 — [MUSS] +**Anforderung:** System-/Dienstprüfungen werden mit Betreiber und Nutzern abgestimmt. +- **Organisatorisch:** Abstimmungs-/Genehmigungsprozess vor Prüfungen (Vermeidung von Betriebsstörungen) etablieren. +- **Technisch:** Prüffenster/Wartungsfenster planen. Referenz: BL-OPS-07. +- **Typische Nachweise:** Abstimmungsnachweis, Freigabe der Prüfung. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-M4 — [MUSS] +**Anforderung:** Die Ergebnisse werden nachvollziehbar gespeichert und der Leitung berichtet. +- **Organisatorisch:** Berichts- und Ablagepflicht festlegen. +- **Technisch:** Zentrale, zugriffsgeschützte Ablage der Prüfberichte. Referenz: BL-OPS-07. +- **Typische Nachweise:** Prüfberichte, Berichtsvermerk an Leitung. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-M5 — [MUSS] +**Anforderung:** Aus den Ergebnissen werden Maßnahmen abgeleitet und fristgerecht umgesetzt. +- **Organisatorisch:** Maßnahmenverfolgung mit Fristen und Verantwortlichen etablieren. +- **Technisch:** Findings in Maßnahmen-/Ticketsystem überführen und nachhalten. Referenz: BL-OPS-06, BL-OPS-07. +- **Typische Nachweise:** Maßnahmenplan, Umsetzungsnachweise. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-S1 — [SOLL] +**Anforderung:** Prüfungen werden unter Berücksichtigung möglicher Sicherheitsrisiken geplant. +- **Organisatorisch:** Risiken der Prüfung selbst (Störungen, Datenzugriff) vorab bewerten. +- **Technisch:** Schonende Testmodi, Testumgebung bei kritischen Systemen. Referenz: BL-OPS-07. +- **Typische Nachweise:** Prüfplanung mit Risikobetrachtung. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-S2 — [SOLL] +**Anforderung:** Regelmäßige System-/Dienstprüfungen werden durchgeführt. +- **Organisatorisch:** Prüfturnus festlegen. +- **Technisch:** Wiederkehrende Scans/Audits automatisieren. Referenz: BL-OPS-07. +- **Typische Nachweise:** Prüfkalender, wiederkehrende Prüfberichte. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-S3 — [SOLL] +**Anforderung:** Innerhalb angemessener Frist wird ein Prüfbericht erstellt. +- **Organisatorisch:** Berichtsfrist festlegen. +- **Technisch:** Standardisierte Berichtsvorlage/Report-Export. Referenz: BL-OPS-07. +- **Typische Nachweise:** Datierte Prüfberichte. +- **Vorlage:** R10; VA-06 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.6-H1 — [HOCH] +**Anforderung:** Für kritische IT-Systeme/-Dienste sind zusätzliche Prüfanforderungen identifiziert und werden erfüllt. (A) +- **Organisatorisch:** Kritische Systeme bestimmen und erweiterte Prüftiefe/-intervalle festlegen. +- **Technisch:** Dienstspezifische Tests und/oder manuelle Penetrationstests, risikobasierte Intervalle. Referenz: BL-OPS-07. +- **Typische Nachweise:** Pentest-/Prüfberichte kritischer Systeme, Intervallfestlegung. +- **Vorlage:** R10; VA-06; BL-OPS-07 +- **Ressourcen:** ggf. externer Pentest-Dienstleister (Budget); mittel–hoch. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.6-V1 — [SEHR HOCH] +**Anforderung:** IT-Systeme/-Dienste werden regelmäßig auf Schwachstellen gescannt; nicht scanbare Systeme erhalten Schutzmaßnahmen. (C, I, A) +- **Organisatorisch:** Verbindlichen Scan-Turnus und Umgang mit nicht scanbaren Systemen festlegen. +- **Technisch:** Regelmäßige authentifizierte Vulnerability-Scans; für nicht scanbare Systeme Isolation/kompensierende Maßnahmen. Referenz: BL-OPS-07, BL-OPS-06. +- **Typische Nachweise:** Scan-Reports, Liste nicht scanbarer Systeme mit Ersatzmaßnahmen. +- **Vorlage:** R10; VA-06; BL-OPS-07 +- **Ressourcen:** Vulnerability-Scanner (Beschaffung möglich); mittel. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 5.2.7 — Netzwerkmanagement und -segmentierung + +### 5.2.7-M1 — [MUSS] +**Anforderung:** Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und erfüllt. +- **Organisatorisch:** Netzwerkbetriebsvorgaben (Verantwortliche, Konfigurations-/Änderungsregeln, Dokumentationspflicht) festlegen. +- **Technisch:** Zentrale Verwaltung der Netzkomponenten, gehärtete Konfigurationen, Netzdokumentation. Referenz: BL-NET-01 (Netzwerkmanagement/Segmentierung). +- **Typische Nachweise:** Netzbetriebsrichtlinie, Netzplan, Konfigurationsstandards. +- **Vorlage:** R10; BL-NET-01 +- **Ressourcen:** IT-Betrieb/Netzwerk; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.7-M2 — [MUSS] +**Anforderung:** Anforderungen an die Netzsegmentierung sind bestimmt und erfüllt. +- **Organisatorisch:** Segmentierungsvorgaben je Schutzbedarf/Zone festlegen (z. B. Client, Server, OT, DMZ, Gäste). +- **Technisch:** VLANs/Subnetze mit Firewall-/ACL-Kontrolle zwischen Segmenten. Referenz: BL-NET-01, BL-NET-02. +- **Typische Nachweise:** Segmentierungskonzept, Firewall-Regeln zwischen Zonen. +- **Vorlage:** R10; BL-NET-01; BL-NET-02 +- **Ressourcen:** IT-Betrieb/Netzwerk; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.7-S1 — [SOLL] +**Anforderung:** Verfahren für das Management und die Steuerung von Netzwerken sind definiert. +- **Organisatorisch:** Betriebs-/Änderungsverfahren für das Netzwerk dokumentieren. +- **Technisch:** Change-gebundene Netzkonfiguration, Konfigurations-Backups/Versionierung. Referenz: BL-NET-01, BL-OPS-01. +- **Typische Nachweise:** Netzbetriebsverfahren, Konfigurations-Backups. +- **Vorlage:** R10; BL-NET-01 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.7-S2 — [SOLL] +**Anforderung:** Für eine risikobasierte Netzsegmentierung werden die einschlägigen Aspekte berücksichtigt. +- **Organisatorisch:** Segmentierung anhand Risiko/Schutzbedarf und Datenflüssen begründen. +- **Technisch:** Feinere Segmentierung/Mikrosegmentierung für schützenswerte Bereiche. Referenz: BL-NET-01. +- **Typische Nachweise:** Risikobasierte Segmentierungsbegründung, Datenflussanalyse. +- **Vorlage:** R10; BL-NET-01 +- **Ressourcen:** IT-Betrieb/Netzwerk; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.7-H1 — [HOCH] +**Anforderung:** Erweiterte Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und umgesetzt. (C, I, A) +- **Organisatorisch:** Erhöhte Kontrollen für kritische Netzbereiche festlegen (z. B. dediziertes Admin-Netz, strengere Änderungsfreigaben). +- **Technisch:** Out-of-Band-Management, NAC/Portsicherheit, verschlüsseltes Management, Monitoring. Referenz: BL-NET-01, BL-NET-02. +- **Typische Nachweise:** NAC-/Admin-Netz-Konfiguration, Management-Härtung. +- **Vorlage:** R10; BL-NET-01 +- **Ressourcen:** IT-Betrieb/Netzwerk; mittel–hoch. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 5.2.8 — Kontinuität kritischer IT-Dienste (IT-Notfall-/BCM) + +### 5.2.8-M1 — [MUSS] +**Anforderung:** Kritische IT-Dienste sind identifiziert und die Geschäftsauswirkung wird berücksichtigt. +- **Organisatorisch:** Business-Impact-Analyse durchführen, kritische IT-Dienste und Abhängigkeiten bestimmen. +- **Technisch:** Kritikalitätsattribute im Service-/Asset-Inventar pflegen. Referenz: BL-OPS-08 (Kontinuität/BCM). +- **Typische Nachweise:** BIA, Liste kritischer IT-Dienste. +- **Vorlage:** R04; VA-02; BL-OPS-08 +- **Ressourcen:** ISB/IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.8-M2 — [MUSS] +**Anforderung:** Anforderungen und Verantwortlichkeiten für Kontinuität und Wiederherstellung sind bekannt und erfüllt. +- **Organisatorisch:** Verantwortliche und Kontinuitätsanforderungen (Zielzustände, Zuständigkeiten) festlegen und kommunizieren. +- **Technisch:** Wiederherstellungsverfahren je kritischem Dienst dokumentieren. Referenz: BL-OPS-08, BL-OPS-05. +- **Typische Nachweise:** Rollen-/Verantwortungsmatrix, Kontinuitätsanforderungen je Dienst. +- **Vorlage:** R04; VA-02; BL-OPS-08 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.8-S1 — [SOLL] +**Anforderung:** Kritische IT-Systeme sind identifiziert. +- **Organisatorisch:** Neben Diensten auch die unterstützenden kritischen Systeme/Komponenten bestimmen. +- **Technisch:** Abhängigkeitskarte Dienst↔System pflegen. Referenz: BL-OPS-08. +- **Typische Nachweise:** Liste kritischer Systeme, Abhängigkeitsdiagramm. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.2.8-S2 — [SOLL] +**Anforderung:** Eine Kontinuitätsplanung existiert und wird regelmäßig überprüft und aktualisiert. +- **Organisatorisch:** IT-Notfallplan/BCP erstellen und Review-Turnus festlegen. +- **Technisch:** Wiederanlaufpläne, Notfallkonfigurationen dokumentieren und pflegen. Referenz: BL-OPS-08. +- **Typische Nachweise:** IT-Notfallplan, Review-Historie. +- **Vorlage:** R04; VA-02; BL-OPS-08 +- **Ressourcen:** ISB/IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.8-S3 — [SOLL] +**Anforderung:** Die Kontinuitätsplanung umfasst mindestens (D)DoS, Ransomware/Sabotage, Systemausfall und Naturkatastrophen. +- **Organisatorisch:** Szenariokatalog festlegen und Maßnahmen je Szenario planen. +- **Technisch:** Szenariospezifische Vorkehrungen (DDoS-Schutz, Ransomware-Wiederanlauf aus sauberem Backup, Redundanz). Referenz: BL-OPS-08, BL-OPS-05. +- **Typische Nachweise:** Szenarienübersicht mit Maßnahmen. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.8-H1 — [HOCH] +**Anforderung:** Die Kontinuitätsplanung enthält vordefinierte Zeitrahmen (RTO) für den Wiederanlauf. (A) +- **Organisatorisch:** RTO (und ergänzend RPO) je kritischem Dienst festlegen und freigeben. +- **Technisch:** Wiederherstellungsverfahren auf RTO auslegen (Ressourcen, Automatisierung). Referenz: BL-OPS-08, BL-OPS-05. +- **Typische Nachweise:** RTO/RPO-Festlegung, Abgleich mit Wiederanlaufverfahren. +- **Vorlage:** R04; VA-02; BL-OPS-08 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-H2 — [HOCH] +**Anforderung:** Angemessene SLAs mit externen Dienstleistern entsprechend der Kontinuitätsplanung bestehen. (A) +- **Organisatorisch:** Kontinuitäts-/Wiederherstellungszusagen vertraglich (SLA) mit Providern vereinbaren. +- **Technisch:** SLA-Parameter (Verfügbarkeit, Reaktions-/Wiederherstellzeit) mit eigenen RTO abgleichen. Referenz: BL-OPS-08. +- **Typische Nachweise:** SLA-Verträge, Abgleich SLA↔RTO. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** Einkauf/IT; gering. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-H3 — [HOCH] +**Anforderung:** Die Kontinuitätspläne umfassen die Koordination vertraglich vereinbarter Kommunikation mit Geschäftspartnern. (A) +- **Organisatorisch:** Kommunikations-/Meldepflichten gegenüber Kunden/Partnern im Notfall festlegen. +- **Technisch:** Kontaktlisten und Kommunikationskanäle notfallfest bereithalten. Referenz: BL-OPS-08. +- **Typische Nachweise:** Kommunikationsplan, Kontaktverzeichnis. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB/IT; gering. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-H4 — [HOCH] +**Anforderung:** Die Kontinuitätsplanung wird regelmäßig getestet (inkl. vollständiger Wiederherstellung und Zielzeiten). (A) +- **Organisatorisch:** Testturnus und Testszenarien festlegen, Ergebnisse auswerten. +- **Technisch:** Wiederherstellungstests bis in bekannten Zustand, RTO-Messung. Referenz: BL-OPS-08, BL-OPS-05. +- **Typische Nachweise:** Testprotokolle mit Zielzeiterreichung, Lessons Learned. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-H5 — [HOCH] +**Anforderung:** Eine Backup- und Wiederherstellungsstrategie für kritische IT-Dienste ist definiert und umgesetzt. (C, I, A) +- **Organisatorisch:** Backup-Strategie (Umfang, Frequenz, Aufbewahrung, Schutzziele) für kritische Dienste festlegen. +- **Technisch:** Regelmäßige, überwachte Backups mit Verschlüsselung und getrennter Ablage. Referenz: BL-OPS-05 (Backup). +- **Typische Nachweise:** Backup-Konzept, Backup-Reports. +- **Vorlage:** R04; VA-02; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-H6 — [HOCH] +**Anforderung:** Backups kritischer IT-Dienste sind gegen unbefugte Veränderung/Löschung durch Schadsoftware geschützt. (I, A) +- **Organisatorisch:** Schutzanforderung gegen Ransomware-Zugriff auf Backups festschreiben. +- **Technisch:** Immutable/WORM-Backups, Offline-/Air-Gap-Kopie, getrennte Backup-Credentials. Referenz: BL-OPS-05. +- **Typische Nachweise:** Immutable-/Offline-Backup-Konfiguration. +- **Vorlage:** R04; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-H7 — [HOCH] +**Anforderung:** Backups kritischer IT-Dienste sind gegen unbefugten Zugriff durch Schadsoftware oder Betreiber geschützt. (C, I) +- **Organisatorisch:** Vertraulichkeitsschutz für Backups (auch bei externem Betrieb) festlegen. +- **Technisch:** Verschlüsselung der Backups mit eigener Schlüsselhoheit, strikte Zugriffstrennung. Referenz: BL-OPS-05, BL-CRY-03. +- **Typische Nachweise:** Backup-Verschlüsselung, Zugriffskonzept. +- **Vorlage:** R04; BL-OPS-05; BL-CRY-03 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.8-V1 — [SEHR HOCH] +**Anforderung:** Die Kontinuitätsplanung ist mit den Kontinuitätsplänen relevanter externer Dienstleister abgestimmt. (A) +- **Organisatorisch:** Gemeinsame Abstimmung/Verzahnung der BCM-Pläne mit kritischen Providern. +- **Technisch:** End-to-End-Wiederanlaufketten über Provider hinweg dokumentieren. Referenz: BL-OPS-08. +- **Typische Nachweise:** Abgestimmte BCM-Pläne, Provider-Bestätigungen. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** ISB/Einkauf; mittel. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +### 5.2.8-V2 — [SEHR HOCH] +**Anforderung:** Fortführung wesentlicher Kern-/Geschäftsfunktionen mit minimalem Verlust an Betriebskontinuität ist möglich. +- **Organisatorisch:** Notbetriebskonzepte für Kernfunktionen definieren. +- **Technisch:** Hochverfügbarkeit/Redundanz und Failover für Kernfunktionen. Referenz: BL-OPS-08. +- **Typische Nachweise:** Notbetriebs-/HA-Konzept, Failover-Nachweis. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** IT-Betrieb; hoch. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +### 5.2.8-V3 — [SEHR HOCH] +**Anforderung:** Die Kontinuitätsplanung wird regelmäßig getestet; Szenarien, Ergebnisse und Lessons Learned werden aufgezeichnet. (I, A) +- **Organisatorisch:** Umfassendes Testprogramm mit Dokumentationspflicht etablieren. +- **Technisch:** Realitätsnahe Failover-/Wiederherstellungstests, Auswertung und Nachsteuerung. Referenz: BL-OPS-08. +- **Typische Nachweise:** Testberichte mit Szenarien und Lessons Learned. +- **Vorlage:** R04; VA-02 +- **Ressourcen:** IT-Betrieb; mittel–hoch. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 5.2.9 — Datensicherung und Wiederherstellung (Backup) + +### 5.2.9-M1 — [MUSS] +**Anforderung:** Backup-Konzepte existieren für relevante IT-Systeme; Schutzmaßnahmen für C/I/A der Sicherungen werden berücksichtigt. +- **Organisatorisch:** Backup-Konzept je System/Datenbestand (Umfang, Frequenz, Aufbewahrung, Verantwortliche) erstellen. +- **Technisch:** Automatisierte Backups mit Verschlüsselung (C), Integritätsprüfung (I) und redundanter Ablage (A). Referenz: BL-OPS-05 (Backup). +- **Typische Nachweise:** Backup-Konzept, Backup-Job-Reports. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.9-M2 — [MUSS] +**Anforderung:** Wiederherstellungskonzepte existieren für relevante IT-Dienste. +- **Organisatorisch:** Wiederherstellungsverfahren je Dienst dokumentieren (Schritte, Zuständige, Voraussetzungen). +- **Technisch:** Restore-Prozeduren mit Reihenfolge und Abhängigkeiten hinterlegen. Referenz: BL-OPS-05. +- **Typische Nachweise:** Wiederherstellungskonzept, Restore-Anleitung. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.9-S1 — [SOLL] +**Anforderung:** Für jeden relevanten IT-Dienst existiert ein Backup-/Wiederherstellungskonzept inkl. Abhängigkeiten und Reihenfolge. +- **Organisatorisch:** Konzepte diensteweise vervollständigen und Wiederanlaufreihenfolge festlegen. +- **Technisch:** Abhängigkeits-/Reihenfolgeplan in Restore-Runbooks abbilden. Referenz: BL-OPS-05, BL-OPS-08. +- **Typische Nachweise:** Restore-Runbooks mit Abhängigkeitsreihenfolge. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.2.9-H1 — [HOCH] +**Anforderung:** Backup-/Wiederherstellungskonzepte werden methodisch in regelmäßigen Abständen überprüft. (A) +- **Organisatorisch:** Review-Turnus für die Konzepte festlegen. +- **Technisch:** Abgleich Konzept↔tatsächliche Systemlandschaft/Backup-Jobs. Referenz: BL-OPS-05. +- **Typische Nachweise:** Review-Protokolle der Backup-Konzepte. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.9-H2 — [HOCH] +**Anforderung:** Die grundsätzliche Wiederherstellbarkeit wird berücksichtigt und getestet. (I, A) +- **Organisatorisch:** Restore-Tests einplanen (Stichproben/Testsysteme). +- **Technisch:** Regelmäßige Test-Restores auf Testsystem, Integritätsprüfung der Rücksicherung. Referenz: BL-OPS-05. +- **Typische Nachweise:** Restore-Testprotokolle. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; gering–mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 5.2.9-V1 — [SEHR HOCH] +**Anforderung:** (Zusätzliche) Backups über Offline-Verfahren, immutable Backups oder isolierte IAM-Lösung. (I, A) +- **Organisatorisch:** Ransomware-resistente Backup-Linie für sehr hohen Schutzbedarf festlegen. +- **Technisch:** Air-Gap/Offline-Kopien, Immutable-Storage, getrennte/isolierte Backup-Identitäten. Referenz: BL-OPS-05. +- **Typische Nachweise:** Konfiguration Offline-/Immutable-Backup, getrennte IAM-Nachweise. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; mittel–hoch. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +### 5.2.9-V2 — [SEHR HOCH] +**Anforderung:** Wiederherstellungsverfahren werden methodisch in regelmäßigen Abständen technisch getestet. (I, A) +- **Organisatorisch:** Verbindliches Restore-Testprogramm mit Auswertung etablieren. +- **Technisch:** Vollständige technische Restore-Tests inkl. Funktionsprüfung des wiederhergestellten Dienstes. Referenz: BL-OPS-05. +- **Typische Nachweise:** Technische Restore-Testberichte. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; mittel. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +### 5.2.9-V3 — [SEHR HOCH] +**Anforderung:** Geografische Redundanz wird in Backup-/Wiederherstellungskonzepten berücksichtigt. (A) +- **Organisatorisch:** Vorgabe zur räumlich getrennten Aufbewahrung von Sicherungen. +- **Technisch:** Backup-Replikation an zweiten Standort/Region, georedundante Ablage. Referenz: BL-OPS-05. +- **Typische Nachweise:** Nachweis georedundanter Backup-Ablage. +- **Vorlage:** R10; VA-05; BL-OPS-05 +- **Ressourcen:** IT-Betrieb; mittel–hoch. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 5.3.1 — Sichere Entwicklung und Beschaffung von IT-Diensten + +### 5.3.1-M1 — [MUSS] +**Anforderung:** Die mit Design und Entwicklung eines IT-Dienstes verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt. +- **Organisatorisch:** Security-by-Design im Entwicklungsprozess verankern (Sicherheitsanforderungen früh definieren, Freigaben). +- **Technisch:** Sichere Entwicklungsstandards, Threat Modeling, Code-/Konfigurationsvorgaben. Referenz: BL-OPS-02 (Umgebungstrennung), BL-CRY-01. +- **Typische Nachweise:** Sicherheitsanforderungen im Design, Secure-Development-Vorgaben. +- **Vorlage:** R11; VA-16; BL-OPS-02 +- **Ressourcen:** Entwicklung/ISB; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-M2 — [MUSS] +**Anforderung:** Die mit Beschaffung/Erweiterung von IT-Diensten und -Komponenten verbundenen Sicherheitsanforderungen sind bestimmt und berücksichtigt. +- **Organisatorisch:** Sicherheitsanforderungen in Beschaffungs-/Ausschreibungsprozess integrieren (Kriterien, Freigabe). +- **Technisch:** Anforderungskataloge/Sicherheitschecklisten für Beschaffung, Prüfung vor Inbetriebnahme. Referenz: BL-OPS-01. +- **Typische Nachweise:** Beschaffungsanforderungen mit Sicherheitskriterien, Freigabedokumente. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** Einkauf/IT/ISB; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-M3 — [MUSS] +**Anforderung:** Informationssicherheitsanforderungen bei Änderungen an entwickelten IT-Diensten werden berücksichtigt. +- **Organisatorisch:** Änderungen an Eigenentwicklungen an den Change-/Secure-Development-Prozess binden. +- **Technisch:** Sicherheitsprüfung/-tests bei Änderungen (SAST/DAST, Review). Referenz: BL-OPS-01, BL-OPS-02. +- **Typische Nachweise:** Change-Records mit Sicherheitsprüfung, Testresultate. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** Entwicklung; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-M4 — [MUSS] +**Anforderung:** Systemabnahmetests werden unter Berücksichtigung der Informationssicherheitsanforderungen durchgeführt. +- **Organisatorisch:** Sicherheitskriterien als Abnahmebedingung festlegen. +- **Technisch:** Security-Testfälle in Abnahmetests, Nachweis vor Go-Live. Referenz: BL-OPS-02. +- **Typische Nachweise:** Abnahmetestprotokolle mit Sicherheitskriterien, Freigabe. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** Entwicklung/QA; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-S1 — [SOLL] +**Anforderung:** Anforderungsspezifikationen werden erstellt. +- **Organisatorisch:** Verbindliche Spezifikation inkl. Sicherheitsanforderungen fordern. +- **Technisch:** Strukturierte Anforderungsdokumentation mit Sicherheitsabschnitt. Referenz: BL-OPS-02. +- **Typische Nachweise:** Anforderungsspezifikationen. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** Entwicklung; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-S2 — [SOLL] +**Anforderung:** Anforderungsspezifikationen werden gegen die Informationssicherheitsanforderungen geprüft. +- **Organisatorisch:** Review der Spezifikation gegen Sicherheitsvorgaben etablieren. +- **Technisch:** Security-Review/Checkliste in der Spezifikationsphase. Referenz: BL-OPS-02. +- **Typische Nachweise:** Review-Vermerk, Prüfcheckliste. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** ISB/Entwicklung; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-S3 — [SOLL] +**Anforderung:** Der IT-Dienst wird vor Produktivnutzung auf Einhaltung der Spezifikationen geprüft. +- **Organisatorisch:** Freigabe vor Produktivsetzung an Spezifikationskonformität binden. +- **Technisch:** Abnahme-/Konformitätstests gegen Spezifikation. Referenz: BL-OPS-02. +- **Typische Nachweise:** Konformitäts-/Abnahmeberichte. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** QA/Entwicklung; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-S4 — [SOLL] +**Anforderung:** Die Nutzung von Produktivdaten zu Testzwecken wird soweit möglich vermieden. +- **Organisatorisch:** Vorgabe zur Vermeidung von Produktivdaten in Tests; Ausnahmen genehmigungspflichtig. +- **Technisch:** Anonymisierung/Pseudonymisierung oder synthetische Testdaten. Referenz: BL-OPS-02. +- **Typische Nachweise:** Testdatenkonzept, Anonymisierungsnachweis. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** Entwicklung; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-S5 — [SOLL] +**Anforderung:** Testsysteme erhalten Schutzmaßnahmen vergleichbar zur Produktivumgebung, wenn Produktivdaten genutzt werden. +- **Organisatorisch:** Bei Produktivdaten im Test gleichwertigen Schutz vorschreiben. +- **Technisch:** Härtung, Zugriffskontrolle und Verschlüsselung der Testumgebung analog Produktion. Referenz: BL-OPS-02. +- **Typische Nachweise:** Schutzmaßnahmen-Nachweis Testumgebung. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** IT-Betrieb/Entwicklung; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.1-V1 — [SEHR HOCH] +**Anforderung:** Die Sicherheit zweckgebauter/wesentlich angepasster Software wird bei Inbetriebnahme, wesentlichen Änderungen oder regelmäßig getestet. (C, I, A) +- **Organisatorisch:** Verbindliche Security-Tests (inkl. Pentest) an definierten Zeitpunkten festlegen. +- **Technisch:** Penetrationstests, SAST/DAST, Dependency-/Supply-Chain-Prüfung. Referenz: BL-OPS-07. +- **Typische Nachweise:** Pentest-/Security-Testberichte, Behebungsnachweise. +- **Vorlage:** R11; VA-16; BL-OPS-07 +- **Ressourcen:** ggf. externer Pentest (Budget); mittel–hoch. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 5.3.2 — Sicherheit von Netzdiensten (Bereitstellung) + +### 5.3.2-M1 — [MUSS] +**Anforderung:** Anforderungen an die Informationssicherheit von Netzdiensten sind bestimmt und erfüllt. +- **Organisatorisch:** Sicherheitsanforderungen je bereitgestelltem Netzdienst festlegen (Verschlüsselung, Auth, Verfügbarkeit). +- **Technisch:** Sichere Konfiguration der Netzdienste, Zugriffskontrolle, Verschlüsselung. Referenz: BL-NET-01, BL-CRY-02. +- **Typische Nachweise:** Sicherheitsanforderungen Netzdienste, Konfigurationsnachweise. +- **Vorlage:** R11; VA-16; BL-NET-01 +- **Ressourcen:** IT-Betrieb/Netzwerk; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.2-S1 — [SOLL] +**Anforderung:** Ein Verfahren zur Absicherung und Nutzung von Netzdiensten ist definiert und umgesetzt. +- **Organisatorisch:** Betriebs-/Nutzungsverfahren für Netzdienste dokumentieren. +- **Technisch:** Standardhärtung, Monitoring und Freigabeprozess für Netzdienste. Referenz: BL-NET-01, BL-NET-02. +- **Typische Nachweise:** Netzdienst-Verfahren, Härtungsstandard. +- **Vorlage:** R11; VA-16; BL-NET-02 +- **Ressourcen:** IT-Betrieb; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.3.2-S2 — [SOLL] +**Anforderung:** Die Anforderungen werden in Form von SLAs vereinbart. +- **Organisatorisch:** Sicherheits-/Verfügbarkeitsanforderungen als SLA (intern/mit Provider) festhalten. +- **Technisch:** SLA-Parameter überwachen. Referenz: BL-NET-01. +- **Typische Nachweise:** SLA-Dokumente, SLA-Monitoring. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** IT/Einkauf; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.3.2-S3 — [SOLL] +**Anforderung:** Angemessene Redundanzlösungen sind umgesetzt. +- **Organisatorisch:** Redundanzbedarf je Netzdienst festlegen. +- **Technisch:** Redundante Anbindungen/Komponenten, Failover. Referenz: BL-NET-01. +- **Typische Nachweise:** Redundanzkonzept, Failover-Nachweis. +- **Vorlage:** R11; VA-16 +- **Ressourcen:** IT-Betrieb/Netzwerk; mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.2-H1 — [HOCH] +**Anforderung:** Verfahren zur Überwachung der Qualität des Netzverkehrs sind definiert und werden durchgeführt. (A) +- **Organisatorisch:** Überwachungsvorgaben (Verfügbarkeit, Qualität) festlegen. +- **Technisch:** Traffic-Flow-Analysen, Verfügbarkeits-/Latenzmessung, Alerting. Referenz: BL-NET-01. +- **Typische Nachweise:** Monitoring-Konfiguration, Qualitäts-/Verfügbarkeitsreports. +- **Vorlage:** R11; VA-16; BL-NET-01 +- **Ressourcen:** Netz-Monitoring-Tool (Beschaffung möglich); mittel. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 5.3.3 — Beendigung von IT-Dienstleistungsverhältnissen + +### 5.3.3-S1 — [SOLL] +**Anforderung:** Eine Beschreibung des Beendigungsprozesses ist vorhanden, an Änderungen angepasst und vertraglich geregelt. +- **Organisatorisch:** Exit-/Offboarding-Prozess für IT-Dienste definieren (Datenrückgabe, sichere Löschung, Rechteentzug) und vertraglich verankern. +- **Technisch:** Nachweisbare Datenrückgabe/-löschung, Widerruf von Zugängen und Schnittstellen. Referenz: BL-OPS-01, BL-IAM-05. +- **Typische Nachweise:** Exit-/Beendigungskonzept, Vertragsklausel, Lösch-/Rückgabenachweis. +- **Vorlage:** R11; BL-OPS-01 +- **Ressourcen:** IT/Einkauf/ISB; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +## Control 5.3.4 — Mandantentrennung bei IT-Diensten + +### 5.3.4-M1 — [MUSS] +**Anforderung:** Eine wirksame Trennung (z. B. Mandantentrennung) verhindert den Zugriff unbefugter Nutzer anderer Organisationen auf eigene Informationen. +- **Organisatorisch:** Trennungsanforderung bei geteilt genutzten (Cloud-)Diensten festlegen und beim Anbieter einfordern. +- **Technisch:** Logische/physische Mandantentrennung, getrennte Berechtigungen und ggf. Verschlüsselung mit eigener Schlüsselhoheit. Referenz: BL-NET-01, BL-CRY-03. +- **Typische Nachweise:** Nachweis Mandantentrennung (Anbieter), Berechtigungs-/Trennungskonzept. +- **Vorlage:** R12; VA-11; BL-NET-01 +- **Ressourcen:** IT/ISB; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.4-S1 — [SOLL] +**Anforderung:** Das Trennungskonzept des Anbieters ist dokumentiert und an Änderungen angepasst. +- **Organisatorisch:** Trennungskonzept des Providers einholen, bewerten und bei Änderungen aktualisieren. +- **Technisch:** Abgleich des Anbieterkonzepts mit eigenen Schutzanforderungen (Isolationsmechanismen, Datenhaltung). Referenz: BL-NET-01. +- **Typische Nachweise:** Dokumentiertes Anbieter-Trennungskonzept, Bewertung/Review. +- **Vorlage:** R12; VA-11 +- **Ressourcen:** ISB; gering. +- **AL-Filter:** AL2 + AL3 + +## Control 5.3.4-KI — Nutzung von KI-/GenAI-Diensten + +### 5.3.4-KI-M1 — [MUSS] +**Anforderung:** Der Einsatz von KI-/GenAI-Diensten ist geregelt; es werden nur freigegebene Dienste genutzt. +- **Organisatorisch:** KI-Nutzungsrichtlinie mit Freigabeprozess und Positivliste zugelassener Dienste etablieren. +- **Technisch:** Nutzung nicht freigegebener KI-Dienste über Web-Proxy/CASB einschränken; Freigabeliste technisch durchsetzen. Referenz: BL-NET-02 (Web-/Dienstfreigaben). +- **Typische Nachweise:** KI-Richtlinie, Liste freigegebener Dienste, Proxy-/CASB-Regeln. +- **Vorlage:** R12; VA-11; BL-NET-02 +- **Ressourcen:** ISB/IT-Betrieb; gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.4-KI-M2 — [MUSS] +**Anforderung:** Die Eingabe vertraulicher/personenbezogener Informationen in nicht freigegebene KI-Dienste ist untersagt; zulässige Datenklassen je Dienst sind definiert. +- **Organisatorisch:** Zulässige Datenklassen je freigegebenem Dienst festlegen und Verbot für nicht freigegebene Dienste kommunizieren. +- **Technisch:** DLP-Regeln zur Erkennung/Blockierung sensibler Eingaben an KI-Endpunkte. Referenz: BL-NET-02. +- **Typische Nachweise:** Datenklassen-Mapping je Dienst, DLP-Regeln, Sensibilisierungsnachweis. +- **Vorlage:** R12; VA-11 +- **Ressourcen:** ISB/IT-Betrieb; ggf. DLP (Beschaffung möglich); gering–mittel. +- **AL-Filter:** AL2 + AL3 + +### 5.3.4-KI-M3 — [MUSS] +**Anforderung:** Bei freigegebenen KI-Diensten ist vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden. +- **Organisatorisch:** Vertrags-/AVV-Prüfung auf No-Training- und Weitergabeklauseln; nur Dienste mit passenden Zusicherungen freigeben. +- **Technisch:** Enterprise-/Business-Tarife mit deaktiviertem Training und Datenresidenz nutzen. Referenz: BL-CRY-03 (Datenhoheit). +- **Typische Nachweise:** Vertrag/AVV mit No-Training-Klausel, Konfigurationsnachweis (Training deaktiviert). +- **Vorlage:** R12; VA-11 +- **Ressourcen:** Einkauf/ISB/Datenschutz; gering. +- **AL-Filter:** AL2 + AL3 + +### 5.3.4-KI-S1 — [SOLL] +**Anforderung:** Ergebnisse von KI-Diensten werden vor geschäftskritischer Verwendung geprüft (Human-in-the-Loop); der Einsatz wird dokumentiert und regulatorische Anforderungen (z. B. EU AI Act) berücksichtigt. +- **Organisatorisch:** Human-in-the-Loop-Vorgabe für kritische Ergebnisse, KI-Einsatzregister und Abgleich mit regulatorischen Pflichten (Risikoklassifizierung nach EU AI Act). +- **Technisch:** Kennzeichnung/Protokollierung von KI-generierten Inhalten, Freigabe-Workflows vor produktiver Nutzung. Referenz: BL-OPS-04 (Protokollierung). +- **Typische Nachweise:** KI-Einsatzregister, Prüf-/Freigabevermerke, AI-Act-Einordnung. +- **Vorlage:** R12; VA-11 +- **Ressourcen:** ISB/Fachbereich/Datenschutz; gering–mittel. +- **AL-Filter:** AL2 + AL3 + + +--- + +# Kapitel 6–7 — Lieferanten & Compliance/Datenschutz + +## Control 6.1.1 — Sicherheit bei Auftragnehmern/Lieferanten (Risikobewertung & Verträge) + +### 6.1.1-M1 — [MUSS] +**Anforderung:** Auftragnehmer und Partner werden einer Sicherheitsrisikobewertung unterzogen. +- **Organisatorisch:** Lieferantenverzeichnis führen und jeden sicherheitsrelevanten Auftragnehmer vor Beauftragung sowie regelmäßig anhand eines standardisierten Risikofragebogens (Kritikalität, verarbeitete Informationswerte, Zugriffsart) bewerten; Verantwortlichkeit im Einkauf/ISB verankern. +- **Technisch:** Bewertungen in einem GRC-/Lieferantenmanagement-Tool oder strukturiert im Ticket-/Vertragssystem erfassen, mit Wiedervorlage/Reassessment-Fristen. +- **Typische Nachweise:** Ausgefüllte Risikobewertungen je Lieferant, Lieferantenverzeichnis mit Kritikalitätseinstufung, Nachweis der Wiedervorlage. +- **Vorlage:** R13; VA-10 +- **Ressourcen:** ISB/Einkauf, moderater Aufwand; GRC-/Lieferantentool optional (Beschaffung möglich). +- **AL-Filter:** AL2 + AL3 + +### 6.1.1-M2 — [MUSS] +**Anforderung:** Ein angemessenes Informationssicherheitsniveau wird durch vertragliche Vereinbarungen mit Auftragnehmern und Partnern sichergestellt. +- **Organisatorisch:** Standardklauseln zur Informationssicherheit (Schutzniveau, Meldepflichten, Auditrechte, Unterauftragnehmer) in Verträge/AGB aufnehmen; Freigabe durch Recht/ISB vor Vertragsschluss. +- **Technisch:** Vertragsvorlagen mit IS-Klauselkatalog im Vertragsmanagement hinterlegen; Versionsverwaltung der Klauseln. +- **Typische Nachweise:** Unterzeichnete Verträge mit IS-Klauseln, Klauselkatalog/Vertragsmuster, Freigabevermerk. +- **Vorlage:** R13; VA-10 +- **Ressourcen:** Recht/Einkauf/ISB, initial erhöht (Klauselerstellung), danach gering. +- **AL-Filter:** AL2 + AL3 + +### 6.1.1-M3 — [MUSS] +**Anforderung:** Sofern zutreffend, werden vertragliche Vereinbarungen mit Auftraggebern/Kunden an Auftragnehmer und Partner weitergegeben. +- **Organisatorisch:** Kundenspezifische Sicherheitsanforderungen (Flow-down) identifizieren und verpflichtend in die Unterverträge übernehmen; Zuordnung Kundenanforderung → Lieferantenvertrag dokumentieren. +- **Technisch:** Anforderungsmatrix/Mapping-Tabelle im Vertrags- oder Anforderungsmanagement pflegen. +- **Typische Nachweise:** Flow-down-Klauseln in Unterverträgen, Mapping Kunden-/Lieferantenanforderungen. +- **Vorlage:** R13 +- **Ressourcen:** Recht/Einkauf, geringer bis moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.1-S1 — [SOLL] +**Anforderung:** Auftragnehmer und Partner sind vertraglich verpflichtet, Anforderungen an ein angemessenes Informationssicherheitsniveau an ihre Unterauftragnehmer weiterzugeben. +- **Organisatorisch:** Verpflichtung zur Weitergabe der IS-Anforderungen an Unterauftragnehmer als Standardklausel festlegen; Genehmigungspflicht für Unterbeauftragung vereinbaren. +- **Technisch:** Klausel im Vertragsmuster hinterlegen; Register der zugelassenen Unterauftragnehmer. +- **Typische Nachweise:** Vertragsklausel zur Weitergabe, Liste/Freigaben von Unterauftragnehmern. +- **Vorlage:** R13; VA-10 +- **Ressourcen:** Recht/Einkauf, geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.1-S2 — [SOLL] +**Anforderung:** Leistungsberichte und Dokumente von Auftragnehmern und Partnern werden geprüft. +- **Organisatorisch:** Regelmäßige Auswertung von Leistungs-/Service-Berichten (SLA-Erfüllung, Sicherheitsnachweise) durch die verantwortliche Fachstelle; Abweichungen nachverfolgen. +- **Technisch:** Berichtseingang und Prüfung im Lieferantenmanagement-/Ticketsystem dokumentieren, mit Fristen. +- **Typische Nachweise:** Geprüfte Leistungsberichte, Prüfvermerke, Maßnahmen-/Eskalationsnachweise. +- **Vorlage:** R13 +- **Ressourcen:** Fachbereich/Einkauf, laufender geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.1-H1 — [HOCH] +**Anforderung:** Es wird nachgewiesen, dass das Informationssicherheitsniveau des Lieferanten dem Schutzbedarf angemessen ist (z. B. geprüfter Fragebogen/Selbstauskunft, Attestierung, Zertifikat, Lieferantenaudit). +- **Organisatorisch:** Für Lieferanten mit hohem Schutzbedarf verbindlichen Nachweistyp festlegen (Selbstauskunft mit Plausibilitätsprüfung, ISO-27001-/TISAX-Nachweis oder Audit) und einholen/bewerten. +- **Technisch:** Nachweise (Zertifikate, ausgefüllte Fragebögen) revisionssicher im GRC-/Lieferantentool ablegen, mit Gültigkeitsüberwachung. +- **Typische Nachweise:** Geprüfte Selbstauskunft, Zertifikat/Attestierung, Auditbericht, Bewertungsvermerk. +- **Vorlage:** R13 +- **Ressourcen:** ISB, erhöhter Aufwand; ggf. Auditkosten (Budget). +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.1-H2 — [HOCH] +**Anforderung:** Der Grad der Erfüllung geforderter Nachweise durch den Lieferanten wird dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. +- **Organisatorisch:** Erfüllungsgrad je geforderten Nachweis dokumentieren und in einem Reassessment-Zyklus sowie anlassbezogen (Vertrags-/Leistungsänderung) neu bewerten. +- **Technisch:** Statusübersicht (offen/erfüllt/abgelaufen) im GRC-Tool mit automatischen Erinnerungen. +- **Typische Nachweise:** Nachweis-Statusübersicht, Reassessment-Protokolle, Änderungshistorie. +- **Vorlage:** R13 +- **Ressourcen:** ISB, laufender moderater Aufwand. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.1-H3 — [HOCH] +**Anforderung:** Die Einhaltung vertraglicher Vereinbarungen durch den Lieferanten wird geprüft, dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. +- **Organisatorisch:** Vertragskonformität (IS-Klauseln, SLAs, Meldepflichten) regelmäßig prüfen; Feststellungen mit Maßnahmen und Eskalation verfolgen. +- **Technisch:** Prüf- und Maßnahmenverfolgung im Lieferanten-/GRC-Tool; Verknüpfung Vertrag ↔ Prüfergebnis. +- **Typische Nachweise:** Prüfprotokolle Vertragskonformität, Maßnahmenliste, Eskalationsnachweise. +- **Vorlage:** R13 +- **Ressourcen:** ISB/Einkauf, laufender moderater Aufwand. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.1-V1 — [SEHR HOCH] +**Anforderung:** Das angemessene Informationssicherheitsniveau sollte durch ein Drittparteien-Audit (angemessenes TISAX-Label o. Ä.) oder ein angemessenes Lieferantenaudit nachgewiesen werden. Ohne Audit muss die Leitung eine risikobasierte Entscheidung zur Fortführung treffen; ein Nachweis dieser Entscheidung existiert. +- **Organisatorisch:** Für Lieferanten mit sehr hohem Schutzbedarf ein passendes TISAX-Label bzw. Lieferantenaudit einfordern; liegt keines vor, dokumentierte, risikobasierte Leitungsentscheidung (Risk Acceptance) herbeiführen. +- **Technisch:** Label-/Auditnachweise und Leitungsentscheid revisionssicher im GRC-Tool ablegen, mit Gültigkeits- und Wiedervorlagesteuerung. +- **Typische Nachweise:** TISAX-Label/Auditbericht, dokumentierte Leitungsentscheidung mit Risikobegründung. +- **Vorlage:** R13 +- **Ressourcen:** Leitung/ISB, hoher Aufwand; Auditkosten (Budget). +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +### 6.1.1-V2 — [SEHR HOCH] +**Anforderung:** Vertragliche Verpflichtungen gegenüber Kunden zur Transparenz von Lieferkettenrisiken werden erfüllt. +- **Organisatorisch:** Kundenanforderungen zur Lieferketten-Transparenz identifizieren und ein Verfahren zur Offenlegung relevanter Lieferkettenrisiken (inkl. Unterauftragnehmer) etablieren. +- **Technisch:** Lieferketten-/Risikoregister mit Zuordnung zu Kundenverträgen; Reporting-Auszüge für Kunden generierbar. +- **Typische Nachweise:** Lieferkettenübersicht, an Kunden erbrachte Transparenznachweise, Vertragsbezug. +- **Vorlage:** R13 +- **Ressourcen:** ISB/Einkauf, erhöhter Aufwand. +- **AL-Filter:** AL3 (sehr hoher Schutzbedarf) + +## Control 6.1.2 — Vertraulichkeitsvereinbarungen (NDA) bei Informationsweitergabe + +### 6.1.2-M1 — [MUSS] +**Anforderung:** Die Vertraulichkeitsanforderungen sind bestimmt und erfüllt. +- **Organisatorisch:** Anlässe und Umfang von Vertraulichkeitsverpflichtungen (welche Informationsklassen, welche Empfänger) bestimmen und in einer Regelung festhalten; Umsetzung sicherstellen. +- **Technisch:** Verknüpfung mit dem Klassifizierungsschema; NDA-Pflicht als Attribut in Vertrags-/Partnerstammdaten. +- **Typische Nachweise:** Dokumentierte Vertraulichkeitsanforderungen, Bezug zum Klassifizierungsschema. +- **Vorlage:** R13; VA-10 +- **Ressourcen:** ISB/Recht, geringer bis moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-M2 — [MUSS] +**Anforderung:** Anforderungen und Verfahren zur Anwendung von Vertraulichkeitsvereinbarungen sind allen Personen bekannt, die schutzbedürftige Informationen weitergeben. +- **Organisatorisch:** Verfahren zur NDA-Anwendung kommunizieren (Onboarding, Richtlinie, Schulung); Ansprechpartner für den NDA-Abschluss benennen. +- **Technisch:** Richtlinie und NDA-Vorlagen im Intranet/Dokumentenmanagement zugänglich machen. +- **Typische Nachweise:** Veröffentlichte Richtlinie/Arbeitsanweisung, Schulungs-/Kenntnisnahmenachweise. +- **Vorlage:** R13 +- **Ressourcen:** ISB, geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-M3 — [MUSS] +**Anforderung:** Gültige Vertraulichkeitsvereinbarungen werden vor der Weitergabe schutzbedürftiger Informationen abgeschlossen. +- **Organisatorisch:** Verbindliche Regel „kein Informationsaustausch ohne gültiges NDA"; NDA-Abschluss als Voraussetzung im Freigabe-/Beschaffungsprozess verankern. +- **Technisch:** NDA-Status als Gate im Workflow (Vertrags-/Ticketsystem) prüfen, bevor Zugriff/Weitergabe erfolgt. +- **Typische Nachweise:** Abgeschlossene, gültige NDAs vor Austauschbeginn, Freigabe-Workflow mit NDA-Prüfung. +- **Vorlage:** R13 +- **Ressourcen:** Recht/Fachbereich, laufender geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-M4 — [MUSS] +**Anforderung:** Die Anforderungen und Verfahren zur Nutzung von Vertraulichkeitsvereinbarungen und zum Umgang mit schutzbedürftigen Informationen werden regelmäßig überprüft. +- **Organisatorisch:** NDA-Verfahren und -Vorlagen in einem festen Turnus sowie bei Rechtsänderungen überprüfen und aktualisieren; Review dokumentieren. +- **Technisch:** Review-Termine/Versionsstände im Dokumentenmanagement mit Wiedervorlage steuern. +- **Typische Nachweise:** Review-Protokolle, Versionshistorie der NDA-Vorlagen/-Richtlinie. +- **Vorlage:** R13 +- **Ressourcen:** ISB/Recht, geringer wiederkehrender Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-S1 — [SOLL] +**Anforderung:** Vorlagen für Vertraulichkeitsvereinbarungen sind vorhanden und auf rechtliche Anwendbarkeit geprüft. +- **Organisatorisch:** Standard-NDA-Vorlagen (ein-/beidseitig) bereitstellen und durch die Rechtsfunktion auf Anwendbarkeit (Jurisdiktion, Durchsetzbarkeit) prüfen lassen. +- **Technisch:** Freigegebene Vorlagen zentral im Dokumentenmanagement, mit Kennzeichnung der geprüften Version. +- **Typische Nachweise:** Freigegebene NDA-Vorlagen, rechtlicher Prüfvermerk. +- **Vorlage:** R13; VA-10 +- **Ressourcen:** Recht, initial moderat. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-S2 — [SOLL] +**Anforderung:** Vertraulichkeitsvereinbarungen umfassen beteiligte Personen/Organisationen, Art der Informationen, Gegenstand, Gültigkeitsdauer und Verantwortlichkeiten der verpflichteten Partei. +- **Organisatorisch:** Mindestinhalte für NDAs verbindlich festlegen und in die Vorlage aufnehmen (Parteien, Informationsarten, Zweck, Laufzeit, Pflichten). +- **Technisch:** Vorlagen-Checkliste/Formularfelder zur Vollständigkeitsprüfung. +- **Typische Nachweise:** NDA-Vorlage mit Pflichtinhalten, Beispielverträge. +- **Vorlage:** R13 +- **Ressourcen:** Recht/ISB, geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-S3 — [SOLL] +**Anforderung:** Vertraulichkeitsvereinbarungen enthalten Regelungen zum Umgang mit schutzbedürftigen Informationen über die Vertragsbeziehung hinaus. +- **Organisatorisch:** Nachvertragliche Pflichten (Rückgabe/Löschung, Fortdauer der Geheimhaltung) verbindlich in NDAs regeln. +- **Technisch:** Entsprechende Standardklausel in der Vorlage hinterlegen. +- **Typische Nachweise:** NDA-Klausel zu nachvertraglichen Pflichten. +- **Vorlage:** R13 +- **Ressourcen:** Recht, geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-S4 — [SOLL] +**Anforderung:** Möglichkeiten zum Nachweis der Einhaltung (z. B. Prüfung durch unabhängige Dritte oder Auditrechte) sind definiert. +- **Organisatorisch:** Prüf-/Auditrechte oder Nachweispflichten zur NDA-Einhaltung in der Vereinbarung verankern. +- **Technisch:** Klausel in Vorlage; Nachverfolgung ausgeübter Prüfrechte im Vertragsmanagement. +- **Typische Nachweise:** Auditrechtsklausel, ggf. durchgeführte Prüfungen/Nachweise. +- **Vorlage:** R13 +- **Ressourcen:** Recht/ISB, geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.2-S5 — [SOLL] +**Anforderung:** Ein Prozess zur Überwachung der Gültigkeitsdauer temporärer Vertraulichkeitsvereinbarungen und zur rechtzeitigen Verlängerung ist definiert und umgesetzt. +- **Organisatorisch:** Fristenmanagement für befristete NDAs mit definierter Verantwortlichkeit und Verlängerungs-/Nachfassprozess etablieren. +- **Technisch:** Ablaufüberwachung mit automatischen Erinnerungen im Vertragsmanagement/Kalender. +- **Typische Nachweise:** Fristenübersicht mit Ablaufdaten, Erinnerungs-/Verlängerungsnachweise. +- **Vorlage:** R13 +- **Ressourcen:** Einkauf/Recht, geringer laufender Aufwand. +- **AL-Filter:** AL2 + AL3 + +## Control 6.1.3 — Sicherheit externer IT-Dienste & geteilte Verantwortlichkeiten + +### 6.1.3-M1 — [MUSS] +**Anforderung:** Die betroffenen IT-Dienste sind identifiziert. +- **Organisatorisch:** Alle genutzten externen IT-Dienste (Cloud/SaaS/Managed Services) erfassen und einem Verantwortlichen zuordnen; Bezug zu verarbeiteten Informationswerten herstellen. +- **Technisch:** Dienstinventar im Asset-/CMDB- oder GRC-Tool führen, verknüpft mit dem Asset-Register. +- **Typische Nachweise:** Inventar externer IT-Dienste, Zuordnung zu Assets/Verantwortlichen. +- **Vorlage:** R13; VA-10 +- **Ressourcen:** IT/ISB, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-M2 — [MUSS] +**Anforderung:** Die für den IT-Dienst relevanten Sicherheitsanforderungen sind bestimmt. +- **Organisatorisch:** Je Dienst die Sicherheitsanforderungen aus Schutzbedarf und Klassifizierung ableiten und dokumentieren (Vertraulichkeit, Integrität, Verfügbarkeit, Standort/Rechtsraum). +- **Technisch:** Anforderungskatalog je Dienst hinterlegen; Abgleich mit Konfigurations-Baselines des Dienstes. +- **Typische Nachweise:** Dokumentierte Sicherheitsanforderungen je Dienst, Schutzbedarfsableitung. +- **Vorlage:** R13 +- **Ressourcen:** ISB/Fachbereich, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-M3 — [MUSS] +**Anforderung:** Die für die Umsetzung der Anforderung verantwortliche Organisation ist definiert und sich ihrer Verantwortung bewusst. +- **Organisatorisch:** Für jede Anforderung festlegen, ob Anbieter oder eigene Organisation zuständig ist, und die Zuständigkeit gegenüber der verantwortlichen Stelle bestätigen. +- **Technisch:** Verantwortungszuordnung im Dienstinventar/Responsibility-Matrix dokumentieren. +- **Typische Nachweise:** Verantwortlichkeitszuordnung je Dienst/Anforderung, Bestätigung der zuständigen Stelle. +- **Vorlage:** R13 +- **Ressourcen:** ISB, geringer Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-M4 — [MUSS] +**Anforderung:** Mechanismen für geteilte Verantwortlichkeiten sind spezifiziert und umgesetzt. +- **Organisatorisch:** Shared-Responsibility-Modell je Dienst festlegen (wer verantwortet welche Kontrolle) und die eigenen Pflichtanteile umsetzen. +- **Technisch:** Verantwortungsmatrix (Anbieter/Kunde) je Kontrollbereich; kundenseitige Konfigurationen (z. B. Zugriffsschutz, Verschlüsselung) gemäß Baseline umsetzen (BL-IAM-01 Passwort/Authentifizierung). +- **Typische Nachweise:** Responsibility-Matrix, umgesetzte kundenseitige Kontrollen, Konfigurationsnachweise. +- **Vorlage:** R13; BL-IAM-01 +- **Ressourcen:** IT/ISB, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-M5 — [MUSS] +**Anforderung:** Die verantwortliche Organisation erfüllt ihre jeweiligen Verantwortlichkeiten. +- **Organisatorisch:** Erfüllung der eigenen und (per Nachweis) der anbieterseitigen Pflichten sicherstellen und regelmäßig kontrollieren. +- **Technisch:** Kontrollnachweise (eigene Konfigurationen, Anbieter-Reports/Zertifikate) sammeln und auswerten. +- **Typische Nachweise:** Nachweise erfüllter Pflichten (eigene und Anbieter), Kontrollberichte. +- **Vorlage:** R13 +- **Ressourcen:** IT/ISB, laufender Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-S1 — [SOLL] +**Anforderung:** Bei IT-Diensten ist die Konfiguration auf Basis der notwendigen Sicherheitsanforderungen konzipiert, umgesetzt und dokumentiert. +- **Organisatorisch:** Sichere Sollkonfiguration je Dienst festlegen, freigeben und dokumentieren; Abweichungen begründen. +- **Technisch:** Konfigurations-Baseline/Hardening-Vorgaben anwenden; Ist-Konfiguration dokumentieren und gegen Soll prüfen (BL-OPS-Härtung). +- **Typische Nachweise:** Konfigurationskonzept/-dokumentation je Dienst, Soll-/Ist-Abgleich. +- **Vorlage:** R13; BL-OPS-01 +- **Ressourcen:** IT, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-S2 — [SOLL] +**Anforderung:** Das verantwortliche Personal ist angemessen geschult. +- **Organisatorisch:** Für die Dienstverwaltung zuständiges Personal gezielt zu Konfiguration/Sicherheit der jeweiligen Dienste schulen. +- **Technisch:** Schulungs-/Zertifizierungsnachweise im Schulungsmanagement erfassen. +- **Typische Nachweise:** Schulungsnachweise, Qualifikationsnachweise des Personals. +- **Vorlage:** R13; VA-12 +- **Ressourcen:** Personal/Budget für Schulungen. +- **AL-Filter:** AL2 + AL3 + +### 6.1.3-H1 — [HOCH] +**Anforderung:** Eine Liste der betroffenen IT-Dienste und der jeweils verantwortlichen IT-Dienstleister existiert. +- **Organisatorisch:** Vollständige, gepflegte Liste der Dienste inkl. verantwortlichem Dienstleister und Kontaktinformationen führen. +- **Technisch:** Dienst-/Dienstleisterregister im CMDB-/GRC-Tool mit Aktualisierungsroutine. +- **Typische Nachweise:** Aktuelle Dienst-/Dienstleisterliste, Pflegehistorie. +- **Vorlage:** R13 +- **Ressourcen:** IT/ISB, geringer laufender Aufwand. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.3-H2 — [HOCH] +**Anforderung:** Die Anwendbarkeit der ISA-Controls wurde bewertet und dokumentiert. +- **Organisatorisch:** Je Dienst die anwendbaren ISA-Controls bestimmen und die Bewertung dokumentieren (Applicability-Statement je Dienst). +- **Technisch:** Control-Mapping je Dienst im GRC-Tool hinterlegen. +- **Typische Nachweise:** Dokumentierte ISA-Anwendbarkeitsbewertung je Dienst. +- **Vorlage:** R13 +- **Ressourcen:** ISB, moderater Aufwand. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.3-H3 — [HOCH] +**Anforderung:** Die Dienstkonfiguration ist in die regelmäßigen Sicherheitsbewertungen einbezogen. +- **Organisatorisch:** Dienstkonfigurationen in den Turnus der internen Sicherheitsüberprüfungen/Audits aufnehmen. +- **Technisch:** Wiederkehrende Konfigurations-Reviews/Compliance-Scans der Dienste; Ergebnisse dokumentieren (BL-OPS-Monitoring). +- **Typische Nachweise:** Prüfpläne mit Diensten, Review-/Scan-Ergebnisse. +- **Vorlage:** R13; VA-15 +- **Ressourcen:** IT/ISB, laufender Aufwand. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.3-H4 — [HOCH] +**Anforderung:** Es wird nachgewiesen, dass die IT-Dienstleister ihre Verantwortung erfüllen. +- **Organisatorisch:** Von Dienstleistern regelmäßig Nachweise (Zertifikate, SOC-/Prüfberichte, SLA-Reports) einfordern und bewerten. +- **Technisch:** Nachweiseingang und -bewertung im Lieferanten-/GRC-Tool mit Gültigkeitsüberwachung. +- **Typische Nachweise:** Anbieterzertifikate/Prüfberichte, Bewertungsvermerke. +- **Vorlage:** R13 +- **Ressourcen:** ISB, laufender moderater Aufwand. +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +### 6.1.3-H5 — [HOCH] +**Anforderung:** Die Integration in lokale Schutzmaßnahmen (z. B. sichere Authentifizierungsmechanismen) ist etabliert und dokumentiert. +- **Organisatorisch:** Anbindung der Dienste an die eigenen Schutzmaßnahmen (zentrale Identität, Zugriffskontrolle, Protokollierung) verbindlich festlegen und dokumentieren. +- **Technisch:** SSO/Federation, MFA und Log-Anbindung an SIEM konfigurieren (BL-IAM-01 Authentifizierung, BL-IAM-02 MFA). +- **Typische Nachweise:** Integrationsdokumentation, SSO-/MFA-Konfiguration, Log-Anbindungsnachweis. +- **Vorlage:** R13; BL-IAM-01; BL-IAM-02 +- **Ressourcen:** IT, erhöhter Aufwand; ggf. Tooling (Beschaffung). +- **AL-Filter:** AL3 (hoher Schutzbedarf) + +## Control 7.1.1 — Einhaltung rechtlicher, regulatorischer & vertraglicher Vorgaben + +### 7.1.1-M1 — [MUSS] +**Anforderung:** Rechtliche, regulatorische und vertragliche Vorgaben mit Relevanz für die Informationssicherheit werden regelmäßig bestimmt. +- **Organisatorisch:** Ein Compliance-/Rechtskataster mit IS-relevanten Vorgaben (Gesetze, Normen, Verträge) führen und regelmäßig sowie anlassbezogen aktualisieren; Verantwortlichkeit benennen. +- **Technisch:** Anforderungsregister/GRC-Tool mit Quellen, Fristen und Verantwortlichen; Wiedervorlage für Updates. +- **Typische Nachweise:** Aktuelles Compliance-Register, Aktualisierungshistorie, Verantwortlichkeitszuordnung. +- **Vorlage:** R14; VA-18 +- **Ressourcen:** ISB/Recht, moderater laufender Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 7.1.1-M2 — [MUSS] +**Anforderung:** Richtlinien zur Einhaltung der Vorgaben sind definiert, umgesetzt und den verantwortlichen Personen kommuniziert. +- **Organisatorisch:** Zu den identifizierten Vorgaben konkrete Umsetzungsrichtlinien/-vorgaben ableiten, umsetzen und den Verantwortlichen bekannt machen. +- **Technisch:** Richtlinien im Dokumentenmanagement/Intranet bereitstellen; Mapping Vorgabe → Richtlinie → Maßnahme. +- **Typische Nachweise:** Veröffentlichte Compliance-Richtlinien, Mapping Vorgabe/Maßnahme, Kommunikations-/Kenntnisnahmenachweise. +- **Vorlage:** R14; VA-18 +- **Ressourcen:** ISB/Recht, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 7.1.1-S1 — [SOLL] +**Anforderung:** Die Integrität von Aufzeichnungen entsprechend rechtlichen, regulatorischen und vertraglichen Vorgaben sowie Geschäftsanforderungen wird berücksichtigt. +- **Organisatorisch:** Aufbewahrungs- und Integritätsanforderungen für nachweispflichtige Aufzeichnungen bestimmen und in Handhabungsvorgaben festlegen. +- **Technisch:** Manipulationssichere/revisionssichere Ablage (WORM, Zugriffsschutz, Protokollierung), ggf. mit definierter Aufbewahrungsdauer (BL-OPS-05 Backup/Aufbewahrung). +- **Typische Nachweise:** Aufbewahrungs-/Integritätsvorgaben, Nachweis revisionssicherer Speicherung. +- **Vorlage:** R14; BL-OPS-05 +- **Ressourcen:** IT/ISB, moderater Aufwand; ggf. Archivierungslösung (Beschaffung). +- **AL-Filter:** AL2 + AL3 + +## Control 7.1.2 — Schutz personenbezogener Daten (Datenschutz) + +### 7.1.2-M1 — [MUSS] +**Anforderung:** Rechtliche und vertragliche Informationssicherheitsanforderungen an Verfahren und Prozesse bei der Verarbeitung personenbezogener Daten sind bestimmt. +- **Organisatorisch:** Verarbeitungen personenbezogener Daten erfassen (Verzeichnis von Verarbeitungstätigkeiten) und die daraus folgenden rechtlichen/vertraglichen IS-Anforderungen (z. B. DSGVO) bestimmen; DSB einbinden. +- **Technisch:** VVT und Anforderungszuordnung im GRC-/Datenschutz-Tool pflegen. +- **Typische Nachweise:** Verzeichnis der Verarbeitungstätigkeiten, dokumentierte Datenschutz-/IS-Anforderungen. +- **Vorlage:** R14; VA-18 +- **Ressourcen:** DSB/ISB, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 7.1.2-M2 — [MUSS] +**Anforderung:** Regelungen zur Einhaltung rechtlicher und vertraglicher Anforderungen an den Schutz personenbezogener Daten sind definiert und den beteiligten Personen bekannt. +- **Organisatorisch:** Datenschutzrichtlinie/-vorgaben (inkl. Betroffenenrechte, Meldepflichten, AVV) definieren und den beteiligten Personen kommunizieren/schulen. +- **Technisch:** Richtlinien und AVV-Vorlagen im Dokumentenmanagement bereitstellen; technische Schutzmaßnahmen (Zugriffsschutz, Verschlüsselung) gemäß Baseline. +- **Typische Nachweise:** Datenschutzrichtlinie, Schulungs-/Kenntnisnahmenachweise, AVV-Vorlagen. +- **Vorlage:** R14; VA-18; BL-IAM-01 +- **Ressourcen:** DSB/ISB, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + +### 7.1.2-M3 — [MUSS] +**Anforderung:** Prozesse und Verfahren zum Schutz personenbezogener Daten sind im Informationssicherheits-Managementsystem berücksichtigt. +- **Organisatorisch:** Datenschutzprozesse (z. B. Betroffenenanfragen, Datenpannen, DSFA) mit dem ISMS verzahnen (gemeinsame Risiko-, Vorfall- und Überprüfungsprozesse). +- **Technisch:** Verknüpfung von Datenschutz- und ISMS-Prozessen in GRC-/Incident-Tools (z. B. gemeinsamer Meldeworkflow für Datenpannen). +- **Typische Nachweise:** Integrierte Prozessdokumentation, Verweise Datenschutz ↔ ISMS (Risiko/Incident), DSFA-Beispiele. +- **Vorlage:** R14; VA-18; VA-09 +- **Ressourcen:** DSB/ISB, moderater Aufwand. +- **AL-Filter:** AL2 + AL3 + + +--- + +# Prototypenschutz (8.x) & Datenschutz (9.x) + +# Prototypenschutz (8.x) + +## Control 8.1.1 — Sicherheitskonzept physische/umgebungsbezogene Sicherheit + +### 8.1.1-M1 — [MUSS] +**Anforderung:** Sicherheitskonzept mit Außenhaut, Sicht-/Einblickschutz, Zutrittsschutz/-kontrolle, Einbruch-Überwachung, dokumentiertem Besuchermanagement und Mandantentrennung. +- **Organisatorisch:** Ein objektbezogenes Sicherheitskonzept je Liegenschaft/Sicherheitsbereich erstellen, das alle sechs Aspekte behandelt, Verantwortlichen (Betreiber/Objektsicherheit) benennen und durch die Leitung freigeben lassen; regelmäßige Review-Zyklen (mind. jährlich) festlegen. +- **Technisch:** Bestandteile technisch belegen (Schließplan, EMA/Videokonzept, Zonenplan mit Sicherheitsbereichen); Schutzbereiche in einem Liegenschaftsplan/Zonenmodell dokumentieren. +- **Typische Nachweise:** Freigegebenes Sicherheitskonzept, Zonen-/Liegenschaftsplan, Review-Protokoll, Zuständigkeitsmatrix. +- **Vorlage:** Richtlinie Prototypenschutz (P01, neu anzulegen); R07 physische Sicherheit; VA-17 Zutritt/Besucher. +- **Ressourcen:** Objektsicherheit/Werkschutz; Erstaufwand für Konzepterstellung (ggf. externe Beratung), danach jährliche Pflege. +- **AL-Filter:** AL2 | AL3 + +### 8.1.1-S1 — [SOLL] +**Anforderung:** Perimetersicherung. +- **Organisatorisch:** Perimeterschutz als eigenen Baustein im Sicherheitskonzept beschreiben (Geltungsbereich Grundstücksgrenze). +- **Technisch:** Umzäunung/Mauer, Toranlagen, ggf. Außenhautdetektion und Beleuchtung; Zufahrtskontrolle festlegen. +- **Typische Nachweise:** Perimeterkonzept, Fotodokumentation, Wartungsnachweise Zaun/Tore. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Investitionsbedarf für bauliche Maßnahmen (Beschaffung/Bau) — führt zu Umsetzungsaufgabe. +- **AL-Filter:** AL2 | AL3 + +## Control 8.1.2 — Perimeterschutz gegen unberechtigten Zutritt + +### 8.1.2-M1 — [MUSS] +**Anforderung:** Der unberechtigte Zutritt zu Liegenschaften ist nicht möglich. +- **Organisatorisch:** Zutrittspunkte inventarisieren, Zufahrts-/Zugangsregelung definieren, Verantwortlichkeit für Perimeter festlegen. +- **Technisch:** Durchgängige Umschließung (Zaun/Mauer/Gebäudefront), gesicherte Tore/Schranken, ggf. Detektion; keine ungesicherten Nebenzugänge. +- **Typische Nachweise:** Perimeterplan, Begehungsprotokoll, Prüfung offener Zugänge. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Bauliche Maßnahmen (Beschaffung/Bau), Werkschutz. +- **AL-Filter:** AL2 | AL3 + +### 8.1.2-S1 — [SOLL] +**Anforderung:** Geeignete künstliche, technische und natürliche Barrieren. +- **Organisatorisch:** Barrierenkonzept mit Kombination aus künstlichen (Zaun/Mauer), technischen (Detektion) und natürlichen (Bewuchs) Barrieren dokumentieren. +- **Technisch:** Zaunsysteme, Detektionstechnik, Geländegestaltung/Bewuchs so anordnen, dass Überwindung erschwert und detektiert wird. +- **Typische Nachweise:** Barrierenkonzept, Lageplan, Fotodokumentation. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Investition bauliche/gärtnerische Maßnahmen. +- **AL-Filter:** AL2 | AL3 + +## Control 8.1.3 — Außenhaut Gebäude/Sicherheitsbereiche + +### 8.1.3-M1 — [MUSS] +**Anforderung:** Der unberechtigte Zutritt in Gebäude/Sicherheitsbereiche ist nicht möglich. +- **Organisatorisch:** Sicherheitsbereiche definieren und abgrenzen; Anforderungen an Außenhaut (Wände, Türen, Fenster, Dach) festlegen. +- **Technisch:** Einbruchhemmende Ausführung der Außenhautkomponenten; keine mit handelsüblichem Werkzeug zu öffnenden Elemente. +- **Typische Nachweise:** Bauunterlagen/Zertifikate der Bauteile, Begehungsprotokoll, Mängelliste. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Bauliche Ertüchtigung (Beschaffung/Bau). +- **AL-Filter:** AL2 | AL3 + +### 8.1.3-S1 — [SOLL] +**Anforderung:** Massive Bauweise (Mauerwerk, Beton, Stahl-/Spannbeton). +- **Organisatorisch:** Bei Neubau/Anmietung massive Bauweise als Anforderung berücksichtigen. +- **Technisch:** Massive Wandkonstruktionen; bei Leichtbau ergänzende Verstärkungen/Detektion vorsehen. +- **Typische Nachweise:** Baubeschreibung, Statik-/Bauunterlagen, Fotodokumentation. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Baulicher Investitionsbedarf. +- **AL-Filter:** AL2 | AL3 + +### 8.1.3-S2 — [SOLL] +**Anforderung:** Fenster und Türen in der Außenhaut in RC2 oder höher. +- **Organisatorisch:** RC-Klasse als Beschaffungsvorgabe für Fenster/Türen setzen; Bestand bewerten. +- **Technisch:** Einbruchhemmende Fenster/Türen nach DIN EN 1627 (RC2+), inkl. Verglasung und Beschlägen. +- **Typische Nachweise:** RC-Zertifikate/Herstellernachweise, Einbaudokumentation. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Beschaffung einbruchhemmender Elemente. +- **AL-Filter:** AL2 | AL3 + +## Control 8.1.4 — Sicht- und Einblickschutz + +### 8.1.4-M1 — [MUSS] +**Anforderung:** Unberechtigter Einblick auf Neuentwicklungen mit hohem/sehr hohem Schutzbedarf ist nicht möglich. +- **Organisatorisch:** Sicht-/Einblickschutz für Sicherheitsbereiche festlegen; Verhaltensregeln (Türen/Tore geschlossen halten) definieren. +- **Technisch:** Sichtschutz an Fenstern/Glasflächen, blickdichte Tore/Vorhänge, bauliche Sichtbarrieren; Positionierung schutzbedürftiger Objekte außerhalb einsehbarer Zonen. +- **Typische Nachweise:** Einblickschutzkonzept, Begehungsprotokoll (Einsehbarkeit), Fotodokumentation. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Beschaffung Sichtschutzmaßnahmen. +- **AL-Filter:** AL2 | AL3 + +### 8.1.4-S1 — [SOLL] +**Anforderung:** Schutz vor Einblick durch relevante Glasflächen. +- **Organisatorisch:** Relevante Glasflächen identifizieren und Sichtschutzmaßnahme je Fläche festlegen. +- **Technisch:** Folierung/Milchglas, Jalousien/Rollos, blickdichte Verglasung. +- **Typische Nachweise:** Liste Glasflächen mit Maßnahme, Fotodokumentation. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Beschaffung/Installation Sichtschutz. +- **AL-Filter:** AL2 | AL3 + +### 8.1.4-S2 — [SOLL] +**Anforderung:** Einsicht in Sicherheitsbereiche durch offene Türen/Tore/Fenster wird verhindert. +- **Organisatorisch:** Verhaltensregel "Tore/Türen geschlossen" verankern, Kontrollen durchführen. +- **Technisch:** Selbstschließende Tore, Schleusen/Sichtschutzvorhänge an Zufahrten, Anordnung so, dass keine direkte Sichtachse besteht. +- **Typische Nachweise:** Verhaltensregeln, Begehungsprotokoll, Fotodokumentation. +- **Vorlage:** P01; R07 physische Sicherheit; VA-17 Zutritt/Besucher. +- **Ressourcen:** Organisatorisch gering; ggf. Nachrüstung Torautomatik. +- **AL-Filter:** AL2 | AL3 + +### 8.1.4-H1 — [HOCH] +**Anforderung:** Räumliche Situation auch geeignet, schutzbedürftig klassifizierte Fahrzeuge vor Einblick zu schützen. +- **Organisatorisch:** Für Fahrzeug-Schutzbedarf erweiterte Einblickschutzanforderungen festlegen (größere Objekte, Rangierflächen). +- **Technisch:** Geschlossene Hallen/Boxen, blickdichte Umhausung, Sichtschutz auch bei Rangier-/Zufahrtswegen. +- **Typische Nachweise:** Einblickschutzkonzept Fahrzeuge, Fotodokumentation, Begehung. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Bauliche Maßnahmen bei hohem Schutzbedarf. +- **AL-Filter:** AL3 (hoher/sehr hoher Schutzbedarf) + +## Control 8.1.5 — Zugangskontrolle Sicherheitsbereiche + +### 8.1.5-M1 — [MUSS] +**Anforderung:** Mindestens eine von drei Maßnahmen: mechanische Schlösser mit dokumentierter Schlüsselvergabe, elektronische Zugangssysteme mit dokumentierter Berechtigungsvergabe oder Personen-Zutrittskontrolle inkl. Dokumentation. +- **Organisatorisch:** Zutrittskontrollverfahren mit dokumentierter Vergabe/Entzug festlegen; Berechtigungen nach Need-to-know. +- **Technisch:** Elektronisches Zutrittskontrollsystem (Ausweis/PIN) mit Protokollierung oder Schließanlage mit Schließplan; alternativ Personenkontrolle mit Zutrittsbuch. +- **Typische Nachweise:** Schließplan/Berechtigungsliste, Zutrittsprotokolle, Vergabe-/Entzugsnachweise. +- **Vorlage:** P01; VA-17 Zutritt/Besucher; R07 physische Sicherheit. +- **Ressourcen:** ZKS-Beschaffung/-Betrieb oder Schließanlage; Werkschutz. +- **AL-Filter:** AL2 | AL3 + +### 8.1.5-H1 — [HOCH] +**Anforderung:** Räumliche Situation auch geeignet, schutzbedürftig klassifizierte Fahrzeuge vor unberechtigtem Zugriff zu schützen. +- **Organisatorisch:** Zutrittsregelung auf Fahrzeug-Abstellbereiche ausdehnen, verschärfte Berechtigung. +- **Technisch:** Separat gesicherte, zutrittsbeschränkte Fahrzeughallen/Boxen mit protokolliertem Zugang. +- **Typische Nachweise:** Berechtigungskonzept Fahrzeugbereiche, Zutrittsprotokolle. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Ggf. bauliche/technische Nachrüstung. +- **AL-Filter:** AL3 (hoher/sehr hoher Schutzbedarf) + +## Control 8.1.6 — Einbruch-Überwachung + +### 8.1.6-M1 — [MUSS] +**Anforderung:** Einbruchmeldeanlage nach DIN EN 50131/VdS mit Alarmverfolgung auf zertifizierten Sicherheitsdienst/Leitstelle — oder 24/7-Bewachung durch zertifizierten Sicherheitsdienst. +- **Organisatorisch:** Überwachungsvariante festlegen (EMA vs. Bewachung), Dienstleister vertraglich binden (zertifiziert). +- **Technisch:** EMA nach DIN EN 50131/VdS mit Aufschaltung auf Leitstelle (DIN 77200/VdS 3138); alternativ Wachdienst rund um die Uhr. +- **Typische Nachweise:** EMA-Attest/VdS-Nachweis, Aufschaltvertrag, Zertifikat Sicherheitsdienst, Wartungsnachweis. +- **Vorlage:** P01; R07 physische Sicherheit; R13 Lieferanten (Wachdienst); VA-10 Lieferanten. +- **Ressourcen:** EMA-Investition + laufende Aufschaltkosten oder Wachdienstvertrag. +- **AL-Filter:** AL2 | AL3 + +### 8.1.6-M2 — [MUSS] +**Anforderung:** Alarmierungspläne sind verfügbar. +- **Organisatorisch:** Alarmierungs-/Interventionsplan mit Eskalation, Verantwortlichen und Kontaktketten erstellen und aktuell halten. +- **Technisch:** Hinterlegung in Leitstelle/EMA; definierte Interventionskräfte. +- **Typische Nachweise:** Alarmierungsplan, Interventionsvereinbarung, Aktualisierungsnachweis. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Organisatorisch; Abstimmung mit Dienstleister. +- **AL-Filter:** AL2 | AL3 + +### 8.1.6-M3 — [MUSS] +**Anforderung:** Eine zeitnahe Alarmverfolgung ist sichergestellt. +- **Organisatorisch:** Reaktions-/Interventionszeiten vertraglich vereinbaren und überprüfen. +- **Technisch:** Aufschaltung auf 24/7-Leitstelle mit definierter Interventionszeit; Funktionstests. +- **Typische Nachweise:** SLA/Interventionsvereinbarung, Alarm-/Interventionsprotokolle, Testberichte. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Laufende Dienstleisterkosten. +- **AL-Filter:** AL2 | AL3 + +## Control 8.1.7 — Dokumentiertes Besuchermanagement + +### 8.1.7-M1 — [MUSS] +**Anforderung:** Anmeldepflicht für alle Besucher. +- **Organisatorisch:** Besucherprozess mit Voranmeldung, Registrierung, Begleitung und Abmeldung definieren. +- **Technisch:** Besuchermanagementsystem oder Besucherbuch mit Ausweisvergabe; Protokollierung Kommen/Gehen. +- **Typische Nachweise:** Besucherprozess, Besucherprotokolle/-liste, Besucherausweise. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Empfang/Werkschutz; ggf. Besuchersystem. +- **AL-Filter:** AL2 | AL3 + +### 8.1.7-M2 — [MUSS] +**Anforderung:** Dokumentierte Verpflichtung zur Geheimhaltung vor dem Zutritt. +- **Organisatorisch:** Besucher vor Zutritt auf Geheimhaltung verpflichten (NDA/Besuchererklärung), Aufbewahrung regeln. +- **Technisch:** Digitale Erfassung/Signatur im Besuchersystem oder unterschriebene Formulare. +- **Typische Nachweise:** Unterzeichnete Geheimhaltungserklärungen, Archiv der Erklärungen. +- **Vorlage:** P01; VA-17 Zutritt/Besucher; R13 Lieferanten (bei Fremdfirmen). +- **Ressourcen:** Organisatorisch gering. +- **AL-Filter:** AL2 | AL3 + +### 8.1.7-M3 — [MUSS] +**Anforderung:** Veröffentlichung von Sicherheits- und Besucherregelungen. +- **Organisatorisch:** Besucher-/Sicherheitsregeln am Empfang und im Sicherheitsbereich aushängen/aushändigen. +- **Technisch:** Aushänge, Merkblätter, Anzeige im Besuchersystem. +- **Typische Nachweise:** Aushang/Merkblatt, Fotodokumentation, Aushändigungsnachweis. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Organisatorisch gering. +- **AL-Filter:** AL2 | AL3 + +### 8.1.7-M4 — [MUSS] +**Anforderung:** Länderspezifische gesetzliche Datenschutzbestimmungen einhalten. +- **Organisatorisch:** Besucherdatenverarbeitung datenschutzkonform gestalten (Rechtsgrundlage, Löschfristen, Information); mit DS-Funktion abstimmen. +- **Technisch:** Zugriffsbeschränkung und automatisierte Löschung der Besucherdaten. +- **Typische Nachweise:** Löschkonzept Besucherdaten, Datenschutzinformation, Eintrag im Verarbeitungsverzeichnis. +- **Vorlage:** P01; VA-17 Zutritt/Besucher; Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz. +- **Ressourcen:** Abstimmung DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +## Control 8.1.8 — Mandantentrennung vor Ort + +### 8.1.8-M1 — [MUSS] +**Anforderung:** Räumliche Trennung durch personelle/technische Maßnahmen nach Kunden/Projekten; ohne Trennung explizite Kundenfreigabe. +- **Organisatorisch:** Trennungskonzept je Kunde/Projekt definieren; bei fehlender Trennung Freigabe der betroffenen Kunden einholen und dokumentieren. +- **Technisch:** Bauliche Abtrennung (Boxen/Bereiche), zutrittsgetrennte Zonen, projektbezogene Berechtigungen. +- **Typische Nachweise:** Trennungskonzept, Zonen-/Berechtigungsplan, ggf. Kundenfreigaben. +- **Vorlage:** P01; R07 physische Sicherheit; R13 Lieferanten. +- **Ressourcen:** Ggf. bauliche Trennung. +- **AL-Filter:** AL2 | AL3 + +### 8.1.8-H1 — [HOCH] +**Anforderung:** Räumliche Situation auch geeignet für Mandantentrennung bei schutzbedürftig klassifizierten Fahrzeugen. +- **Organisatorisch:** Trennungskonzept auf Fahrzeugbereiche ausdehnen. +- **Technisch:** Separate, blickdichte und zutrittsgetrennte Fahrzeughallen/Boxen je Mandant. +- **Typische Nachweise:** Trennungskonzept Fahrzeuge, Belegungsplan, Fotodokumentation. +- **Vorlage:** P01; R07 physische Sicherheit. +- **Ressourcen:** Bauliche Maßnahmen bei hohem Schutzbedarf. +- **AL-Filter:** AL3 (hoher/sehr hoher Schutzbedarf) + +## Control 8.2.1 — Geheimhaltungsvereinbarungen + +### 8.2.1-M1 — [MUSS] +**Anforderung:** Eine Geheimhaltungsvereinbarung. +- **Organisatorisch:** NDA-Vorlage bereitstellen und Prozess festlegen, dass schutzbedürftige Informationen nur mit gültiger NDA weitergegeben werden. +- **Technisch:** Vertragsmanagement mit Ablage/Statusverfolgung der NDAs. +- **Typische Nachweise:** NDA-Vorlage, abgeschlossene NDAs, Vertragsregister. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Recht/Einkauf; organisatorisch. +- **AL-Filter:** AL2 | AL3 + +### 8.2.1-M2 — [MUSS] +**Anforderung:** NDA zwischen Auftragnehmer und Auftraggeber (Firmen-Ebene). +- **Organisatorisch:** Firmen-NDA vor Projektbeginn abschließen; Gültigkeit prüfen. +- **Technisch:** Ablage im Vertragsregister mit Laufzeitüberwachung. +- **Typische Nachweise:** Unterzeichnetes Firmen-NDA, Vertragsregister. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Recht/Einkauf. +- **AL-Filter:** AL2 | AL3 + +### 8.2.1-M3 — [MUSS] +**Anforderung:** Persönliche Verpflichtung aller Mitarbeiter und Projektbeteiligten. +- **Organisatorisch:** Alle Projektbeteiligten persönlich zur Geheimhaltung verpflichten (Onboarding/Projekteinstieg). +- **Technisch:** HR-/Projektsystem mit Erfassung und Nachverfolgung der Verpflichtungen. +- **Typische Nachweise:** Unterzeichnete Einzelverpflichtungen, Projektbeteiligtenliste mit Status. +- **Vorlage:** P01; R13 Lieferanten. +- **Ressourcen:** HR/Projektleitung. +- **AL-Filter:** AL2 | AL3 + +### 8.2.1-M4 — [MUSS] +**Anforderung:** Länderspezifische gesetzliche Datenschutzbestimmungen einhalten. +- **Organisatorisch:** Verpflichtungserklärungen datenschutzkonform gestalten und mit DS-Funktion abstimmen. +- **Technisch:** Zugriffsbeschränkte Ablage personenbezogener Verpflichtungsnachweise. +- **Typische Nachweise:** Datenschutzkonforme Formulare, Ablage-/Löschkonzept. +- **Vorlage:** P01; Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz. +- **Ressourcen:** Abstimmung DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +## Control 8.2.2 — Beauftragung von Unterauftragnehmern + +### 8.2.2-M1 — [MUSS] +**Anforderung:** Freigabe durch den ursprünglichen Auftraggeber. +- **Organisatorisch:** Prozess zur Einholung der Auftraggeber-Freigabe vor Beauftragung von Unterauftragnehmern etablieren. +- **Technisch:** Dokumentierte Freigaben im Vertrags-/Lieferantenmanagement. +- **Typische Nachweise:** Freigabedokument des Auftraggebers, Prozessbeschreibung. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Einkauf/Projektleitung. +- **AL-Filter:** AL2 | AL3 + +### 8.2.2-M2 — [MUSS] +**Anforderung:** Vertragsrechtlich gültige Geheimhaltungsvereinbarung vorhanden. +- **Organisatorisch:** NDA mit Unterauftragnehmer vor Weitergabe abschließen. +- **Technisch:** Vertragsregister mit Gültigkeitsprüfung. +- **Typische Nachweise:** Unterzeichnetes NDA, Vertragsregister. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Recht/Einkauf. +- **AL-Filter:** AL2 | AL3 + +### 8.2.2-M3 — [MUSS] +**Anforderung:** NDA zwischen Auftragnehmer und Unterauftragnehmer (Firmen-Ebene). +- **Organisatorisch:** Firmen-NDA mit Unterauftragnehmer sicherstellen. +- **Technisch:** Ablage/Statusverfolgung im Vertragsregister. +- **Typische Nachweise:** Firmen-NDA Unterauftragnehmer. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Recht/Einkauf. +- **AL-Filter:** AL2 | AL3 + +### 8.2.2-M4 — [MUSS] +**Anforderung:** Persönliche Verpflichtung aller Mitarbeiter/Projektbeteiligten des Unterauftragnehmers. +- **Organisatorisch:** Nachweis der persönlichen Verpflichtungen der Beschäftigten des Unterauftragnehmers einfordern. +- **Technisch:** Erfassung im Lieferantenmanagement. +- **Typische Nachweise:** Bestätigung/Liste der Einzelverpflichtungen des Unterauftragnehmers. +- **Vorlage:** P01; R13 Lieferanten. +- **Ressourcen:** Einkauf/Lieferantenmanagement. +- **AL-Filter:** AL2 | AL3 + +### 8.2.2-M5 — [MUSS] +**Anforderung:** Sicherstellung der Einhaltung der Sicherheitsvorgaben des eigentlichen Kunden (Nachweis eingeholt). +- **Organisatorisch:** Kundenvorgaben vertraglich an Unterauftragnehmer weitergeben und Nachweise einholen. +- **Technisch:** Back-to-back-Verträge, Nachweisablage. +- **Typische Nachweise:** Vertragliche Weitergabe, eingeholte Nachweise/Bestätigungen. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Einkauf/Recht. +- **AL-Filter:** AL2 | AL3 + +### 8.2.2-M6 — [MUSS] +**Anforderung:** Nachweis der Einhaltung der Mindestanforderungen Prototypenschutz des Unterauftragnehmers (z. B. Zertifikat). +- **Organisatorisch:** Nachweis (TISAX-Label Prototypenschutz/Bescheinigung) vor Beauftragung einholen und Gültigkeit prüfen. +- **Technisch:** Lieferantenregister mit Label-/Zertifikatsstatus und Ablaufüberwachung. +- **Typische Nachweise:** TISAX-Label/Zertifikat/Bescheinigung, Lieferantenbewertung. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Einkauf/Lieferantenmanagement. +- **AL-Filter:** AL2 | AL3 + +## Control 8.2.3 — Schulung/Sensibilisierung Umgang mit Prototypen + +### 8.2.3-M1 — [MUSS] +**Anforderung:** Sicherstellung der Durchführung von Schulungen/Sensibilisierung durch die Leitung. +- **Organisatorisch:** Leitung verpflichtet sich zu Schulungsprogramm Prototypenschutz und stellt Ressourcen bereit. +- **Technisch:** Learning-Management/Schulungstracking zur Steuerung. +- **Typische Nachweise:** Managementbeschluss/Leitlinie, Schulungsplan. +- **Vorlage:** P01. +- **Ressourcen:** Leitung; Schulungsbudget. +- **AL-Filter:** AL2 | AL3 + +### 8.2.3-M2 — [MUSS] +**Anforderung:** Schulung bei Projekteinstieg. +- **Organisatorisch:** Erstschulung als Pflichtbestandteil des Projekt-Onboardings festlegen. +- **Technisch:** Onboarding-/LMS-Workflow mit Zutritts-/Freischaltvoraussetzung. +- **Typische Nachweise:** Onboarding-Schulungsnachweise, Teilnehmerlisten. +- **Vorlage:** P01. +- **Ressourcen:** Projektleitung/HR. +- **AL-Filter:** AL2 | AL3 + +### 8.2.3-M3 — [MUSS] +**Anforderung:** Regelmäßige (mind. jährliche) Schulung. +- **Organisatorisch:** Jährliche Wiederholungsschulung planen und einladen. +- **Technisch:** LMS mit Fälligkeits-/Erinnerungssteuerung. +- **Typische Nachweise:** Jahresschulungsplan, Teilnahmenachweise. +- **Vorlage:** P01. +- **Ressourcen:** Schulungsbudget/Zeit. +- **AL-Filter:** AL2 | AL3 + +### 8.2.3-M4 — [MUSS] +**Anforderung:** Sicherstellung der Kenntnisse zu Schutzbedarf und resultierenden Maßnahmen. +- **Organisatorisch:** Schulungsinhalte auf Schutzbedarfsklassen und konkrete Maßnahmen ausrichten; Verständnis prüfen. +- **Technisch:** Lernerfolgskontrolle/Quiz im LMS. +- **Typische Nachweise:** Schulungsunterlagen, Testergebnisse. +- **Vorlage:** P01. +- **Ressourcen:** Fachliche Contenterstellung. +- **AL-Filter:** AL2 | AL3 + +### 8.2.3-M5 — [MUSS] +**Anforderung:** Verpflichtende Teilnahme jedes Mitarbeiters/Projektbeteiligten. +- **Organisatorisch:** Teilnahmepflicht verankern und Eskalation bei Nichtteilnahme regeln. +- **Technisch:** LMS-Pflichtzuweisung mit Statusüberwachung. +- **Typische Nachweise:** Vollständigkeitsreport Teilnahme, Eskalationsnachweise. +- **Vorlage:** P01. +- **Ressourcen:** HR/Projektleitung. +- **AL-Filter:** AL2 | AL3 + +### 8.2.3-M6 — [MUSS] +**Anforderung:** Dokumentation der Durchführungen. +- **Organisatorisch:** Schulungsnachweise revisionssicher aufbewahren. +- **Technisch:** LMS-Reporting/Nachweisarchiv. +- **Typische Nachweise:** Teilnahmeprotokolle, Zertifikate, Schulungsregister. +- **Vorlage:** P01. +- **Ressourcen:** Organisatorisch gering. +- **AL-Filter:** AL2 | AL3 + +### 8.2.3-M7 — [MUSS] +**Anforderung:** Schulungskonzept Prototypenschutz ist Teil des allgemeinen Schulungskonzepts (vgl. IS 2.1.3). +- **Organisatorisch:** Prototypenschutz-Modul in das ISMS-Awareness-Konzept integrieren. +- **Technisch:** Gemeinsames LMS-Curriculum mit Prototypen-Modul. +- **Typische Nachweise:** Übergreifendes Schulungskonzept mit Prototypenmodul. +- **Vorlage:** P01. +- **Ressourcen:** Abstimmung ISB/HR. +- **AL-Filter:** AL2 | AL3 + +## Control 8.2.4 — Sicherheitseinstufung des Projekts bekannt + +### 8.2.4-M1 — [MUSS] +**Anforderung:** Jedem Projektbeteiligten sind Sicherheitseinstufung und -vorgaben je Projektfortschritt bekannt. +- **Organisatorisch:** Sicherheitseinstufung und Vorgaben je Projektphase kommunizieren und aktualisieren. +- **Technisch:** Projektinfomappe/Portal mit stufenbezogenen Vorgaben. +- **Typische Nachweise:** Kommunikationsnachweise, Kenntnisnahmebestätigungen, Projektakte. +- **Vorlage:** P01. +- **Ressourcen:** Projektleitung. +- **AL-Filter:** AL2 | AL3 + +### 8.2.4-M2 — [MUSS] +**Anforderung:** Berücksichtigung von Stufenplänen, Geheimhaltung/Tarnung, Entwicklungsrichtlinien. +- **Organisatorisch:** Stufenplan und Tarn-/Entwicklungsvorgaben des Auftraggebers in Projektvorgaben aufnehmen. +- **Technisch:** Ablage der Stufenpläne im Projektsystem. +- **Typische Nachweise:** Stufenplan, Tarnvorgaben, Entwicklungsrichtlinien im Projekt. +- **Vorlage:** P01. +- **Ressourcen:** Projektleitung. +- **AL-Filter:** AL2 | AL3 + +### 8.2.4-M3 — [MUSS] +**Anforderung:** Berücksichtigung als IS-Anforderung des Projekts (vgl. IS 1.2.3 und 7.1.1). +- **Organisatorisch:** Prototypenanforderungen in die Projekt-IS-Anforderungen/-Risikobetrachtung überführen. +- **Technisch:** Verknüpfung mit ISMS-Projektrisikomanagement. +- **Typische Nachweise:** IS-Anforderungsliste/Risikoregister des Projekts. +- **Vorlage:** P01. +- **Ressourcen:** Abstimmung ISB/Projekt. +- **AL-Filter:** AL2 | AL3 + +## Control 8.2.5 — Prozess Zutrittsvergabe Sicherheitsbereiche + +### 8.2.5-M1 — [MUSS] +**Anforderung:** Verantwortlichkeiten für die Zutrittsvergabe eindeutig geregelt und dokumentiert. +- **Organisatorisch:** Rollen für Beantragung, Genehmigung und Vergabe festlegen und dokumentieren. +- **Technisch:** Rollen-/Rechtematrix im Zutrittssystem. +- **Typische Nachweise:** Zuständigkeits-/Rollenmatrix, Prozessbeschreibung. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Objektsicherheit. +- **AL-Filter:** AL2 | AL3 + +### 8.2.5-M2 — [MUSS] +**Anforderung:** Prozess bei Neuvergabe, Änderung und Löschung von Zutrittsberechtigungen. +- **Organisatorisch:** Lebenszyklusprozess (Antrag/Genehmigung/Änderung/Entzug, inkl. Austritt) definieren; regelmäßige Rezertifizierung. +- **Technisch:** Workflow im Zutrittssystem, automatischer Entzug bei Austritt. +- **Typische Nachweise:** Prozessbeschreibung, Vergabe-/Entzugsprotokolle, Rezertifizierungsnachweise. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Objektsicherheit/HR-Schnittstelle. +- **AL-Filter:** AL2 | AL3 + +### 8.2.5-M3 — [MUSS] +**Anforderung:** Verhaltensregeln bei Verlust/Diebstahl von Schließmitteln. +- **Organisatorisch:** Meldeweg und Sofortmaßnahmen (Sperrung/Umstellung) festlegen. +- **Technisch:** Sofortsperrung elektronischer Medien; bei mechanischen Schlössern Schließzylindertausch. +- **Typische Nachweise:** Verfahrensanweisung, Verlustmeldungen, Sperr-/Tauschnachweise. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Objektsicherheit; ggf. Zylindertausch-Budget. +- **AL-Filter:** AL2 | AL3 + +## Control 8.2.6 — Regelungen Bildaufzeichnung/Bildmaterial + +### 8.2.6-M1 — [MUSS] +**Anforderung:** Genehmigungsverfahren zur Bildaufzeichnung. +- **Organisatorisch:** Genehmigungsprozess mit Verantwortlichen und Freigabekriterien definieren. +- **Technisch:** Antrags-/Freigabeworkflow, dokumentierte Freigaben. +- **Typische Nachweise:** Verfahrensbeschreibung, Freigabedokumente. +- **Vorlage:** P01. +- **Ressourcen:** Projektleitung/Objektsicherheit. +- **AL-Filter:** AL2 | AL3 + +### 8.2.6-M2 — [MUSS] +**Anforderung:** Klassifizierung/Einstufung von Bildmaterial festlegen. +- **Organisatorisch:** Einstufungsschema für Bildmaterial an Informationsklassifizierung anlehnen. +- **Technisch:** Kennzeichnung/Metadaten, Ablage nach Klassifizierung. +- **Typische Nachweise:** Klassifizierungsschema, klassifiziertes Bildmaterial. +- **Vorlage:** P01. +- **Ressourcen:** Organisatorisch. +- **AL-Filter:** AL2 | AL3 + +### 8.2.6-M3 — [MUSS] +**Anforderung:** Sichere Lagerung/Speicherung von Bildmaterial. +- **Organisatorisch:** Ablageorte und Zugriffsberechtigungen nach Need-to-know festlegen. +- **Technisch:** Verschlüsselte/zugriffsbeschränkte Speicherung, Berechtigungssteuerung. +- **Typische Nachweise:** Ablage-/Berechtigungskonzept, Zugriffsnachweise. +- **Vorlage:** P01. +- **Ressourcen:** IT/Objektsicherheit. +- **AL-Filter:** AL2 | AL3 + +### 8.2.6-M4 — [MUSS] +**Anforderung:** Sichere Löschung/Entsorgung nicht mehr benötigten Bildmaterials. +- **Organisatorisch:** Löschfristen und Löschprozess definieren. +- **Technisch:** Sichere Löschverfahren/Datenträgervernichtung mit Protokoll. +- **Typische Nachweise:** Löschkonzept, Lösch-/Vernichtungsprotokolle. +- **Vorlage:** P01. +- **Ressourcen:** IT/Objektsicherheit. +- **AL-Filter:** AL2 | AL3 + +### 8.2.6-M5 — [MUSS] +**Anforderung:** Abgesicherte Weitergabe/Versand nur an Empfangsberechtigte. +- **Organisatorisch:** Empfängerkreis und Freigabe für Versand definieren. +- **Technisch:** Verschlüsselter Transfer/gesicherte Freigabeplattform, Empfängerprüfung. +- **Typische Nachweise:** Versandregelung, Übermittlungsnachweise, Empfängerfreigaben. +- **Vorlage:** P01. +- **Ressourcen:** IT. +- **AL-Filter:** AL2 | AL3 + +## Control 8.2.7 — Mitführen/Nutzung mobiler Video-/Fotogeräte + +### 8.2.7-M1 — [MUSS] +**Anforderung:** Festlegung für das Mitführen (z. B. mit/ohne Versiegelung). +- **Organisatorisch:** Regeln zum Mitführen mobiler Geräte in Sicherheitsbereichen festlegen (Versiegelung/Abgabe). +- **Technisch:** Kamera-Versiegelung, Verwahrung am Eingang, Kennzeichnung. +- **Typische Nachweise:** Regelung Mitführen, Versiegelungs-/Verwahrnachweise, Aushang. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Objektsicherheit; Versiegelungsmaterial. +- **AL-Filter:** AL2 | AL3 + +### 8.2.7-M2 — [MUSS] +**Anforderung:** Festlegung für die Nutzung (z. B. Telefonieren, Fotografieren). +- **Organisatorisch:** Nutzungsregeln (Foto-/Aufnahmeverbot, Telefonie) je Bereich festlegen und kommunizieren. +- **Technisch:** Beschilderung/Kennzeichnung, Kontrollen durch Werkschutz. +- **Typische Nachweise:** Nutzungsregelung, Beschilderung, Kontrollprotokolle. +- **Vorlage:** P01; VA-17 Zutritt/Besucher. +- **Ressourcen:** Objektsicherheit. +- **AL-Filter:** AL2 | AL3 + +## Control 8.3.1 — Transporte nach Auftraggebervorgaben + +### 8.3.1-M1 — [MUSS] +**Anforderung:** Prozess zur Einholung auftraggeberspezifischer Transportanforderungen beschrieben und implementiert. +- **Organisatorisch:** Prozess definieren, der vor Transport die Kundenvorgaben einholt und in Transportaufträge überführt. +- **Technisch:** Ablage der Vorgaben und Verknüpfung mit Transportaufträgen. +- **Typische Nachweise:** Prozessbeschreibung, eingeholte Kundenvorgaben. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Logistik/Projektleitung. +- **AL-Filter:** AL2 | AL3 + +### 8.3.1-M2 — [MUSS] +**Anforderung:** Vom Auftraggeber definierte Sicherheitsvorgaben sind bekannt und werden eingehalten. +- **Organisatorisch:** Vorgaben an ausführende Stellen/Dienstleister kommunizieren und Einhaltung überwachen. +- **Technisch:** Transportbegleitpapiere mit Sicherheitsanforderungen, Tracking. +- **Typische Nachweise:** Kommunikationsnachweis, Transportdokumentation, Kontrollen. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Logistik. +- **AL-Filter:** AL2 | AL3 + +### 8.3.1-M3 — [MUSS] +**Anforderung:** Nur vom Auftraggeber freigegebene Logistik-/Transportunternehmen verwenden. +- **Organisatorisch:** Freigegebene Dienstleister listen und ausschließlich diese beauftragen. +- **Technisch:** Lieferantenregister mit Freigabestatus, Sperrung nicht freigegebener. +- **Typische Nachweise:** Freigabeliste, Beauftragungsnachweise. +- **Vorlage:** P01; R13 Lieferanten; VA-10 Lieferanten. +- **Ressourcen:** Einkauf/Logistik. +- **AL-Filter:** AL2 | AL3 + +### 8.3.1-M4 — [MUSS] +**Anforderung:** Prozess zur Meldung aller sicherheitsrelevanten Ereignisse an den Auftraggeber. +- **Organisatorisch:** Meldeprozess mit Fristen und Kontaktketten zum Auftraggeber definieren. +- **Technisch:** Vorfall-/Meldeworkflow mit Dokumentation. +- **Typische Nachweise:** Meldeprozess, Vorfallsmeldungen/-protokolle. +- **Vorlage:** P01; R13 Lieferanten. +- **Ressourcen:** Logistik/Projektleitung. +- **AL-Filter:** AL2 | AL3 + +## Control 8.3.2 — Abstellen/Lagern nach Auftraggebervorgaben + +### 8.3.2-M1 — [MUSS] +**Anforderung:** Auftraggebervorgaben zum Abstellen/Lagern sind nachweislich bekannt und werden eingehalten. +- **Organisatorisch:** Kundenvorgaben zu Lager-/Abstellbedingungen einholen, kommunizieren und Einhaltung prüfen. +- **Technisch:** Gesicherte, zutritts-/einblickgeschützte Abstell-/Lagerbereiche gemäß Vorgaben. +- **Typische Nachweise:** Vorgabendokument, Kenntnisnahmenachweise, Begehungs-/Kontrollprotokolle. +- **Vorlage:** P01; R07 physische Sicherheit; R13 Lieferanten. +- **Ressourcen:** Logistik/Objektsicherheit. +- **AL-Filter:** AL2 | AL3 + +## Control 8.4.1 — Tarnung von Versuchsfahrzeugen + +> Im aktuellen Prüfziel (Prototypenteile/-komponenten) n.a. — nur relevant bei Prüfziel Fahrzeuge/Erprobung/Veranstaltungen. + +## Control 8.4.2 — Test-/Erprobungsgelände + +> Im aktuellen Prüfziel (Prototypenteile/-komponenten) n.a. — nur relevant bei Prüfziel Fahrzeuge/Erprobung/Veranstaltungen. + +## Control 8.4.3 — Erprobungsfahrten öffentliche Straßen + +> Im aktuellen Prüfziel (Prototypenteile/-komponenten) n.a. — nur relevant bei Prüfziel Fahrzeuge/Erprobung/Veranstaltungen. + +## Control 8.5.1 — Ausstellungen und Veranstaltungen + +> Im aktuellen Prüfziel (Prototypenteile/-komponenten) n.a. — nur relevant bei Prüfziel Fahrzeuge/Erprobung/Veranstaltungen. + +## Control 8.5.2 — Film- und Fotoshootings + +> Im aktuellen Prüfziel (Prototypenteile/-komponenten) n.a. — nur relevant bei Prüfziel Fahrzeuge/Erprobung/Veranstaltungen. + +# Datenschutz (9.x) + +## Control 9.1.1 — Richtlinien zum Datenschutz + +### 9.1.1-M1 — [MUSS] +**Anforderung:** Richtlinie ist erstellt, wird regelmäßig aktualisiert und von der Leitung freigegeben. +- **Organisatorisch:** Datenschutzrichtlinie erstellen, durch Leitung freigeben, Review-Zyklus (mind. jährlich) und Verantwortliche festlegen; an Beschäftigte kommunizieren. +- **Technisch:** Versionierte Ablage im Dokumentenmanagement mit Freigabe-Workflow und Wiedervorlage. +- **Typische Nachweise:** Freigegebene Datenschutzrichtlinie, Freigabevermerk, Versions-/Reviewhistorie. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/Leitung; jährliche Pflege. +- **AL-Filter:** AL2 | AL3 + +## Control 9.2.1 — Verantwortlichkeiten für Datenschutz + +### 9.2.1-M1 — [MUSS] +**Anforderung:** Bestellung eines DSB (sofern gesetzlich erforderlich, Art. 37 DSGVO) bzw. Festlegung einer Datenschutzfunktion. +- **Organisatorisch:** Prüfen, ob DSB-Pflicht besteht; DSB förmlich bestellen oder Datenschutzfunktion benennen; Aufgaben festlegen. +- **Technisch:** Ablage der Bestellurkunde/Funktionsbeschreibung im DMS. +- **Typische Nachweise:** Bestellurkunde/Benennung, Aufgabenbeschreibung, Meldung an Aufsichtsbehörde (falls DSB). +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** Leitung; ggf. externer DSB (Budget). +- **AL-Filter:** AL2 | AL3 + +### 9.2.1-M2 — [MUSS] +**Anforderung:** Veröffentlichung der Kontaktdaten (z. B. im Internet). +- **Organisatorisch:** Kontaktdaten der DS-Funktion/DSB veröffentlichen und aktuell halten. +- **Technisch:** Angabe in Datenschutzerklärung/Website, ggf. Meldung an Aufsichtsbehörde. +- **Typische Nachweise:** Website-/Impressumseintrag, Datenschutzerklärung, Behördenmeldung. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** Organisatorisch gering. +- **AL-Filter:** AL2 | AL3 + +### 9.2.1-M3 — [MUSS] +**Anforderung:** Eingliederung in die Unternehmensstruktur. +- **Organisatorisch:** Stellung der DS-Funktion (Weisungsfreiheit, direkte Berichtslinie an Leitung, Unabhängigkeit) im Organigramm verankern. +- **Technisch:** Dokumentation in Organigramm/Funktionsbeschreibung. +- **Typische Nachweise:** Organigramm, Rollen-/Funktionsbeschreibung. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** Organisatorisch. +- **AL-Filter:** AL2 | AL3 + +### 9.2.1-M4 — [MUSS] +**Anforderung:** Ausübung der Kontrollpflichten aus Art. 39 Abs. 1 lit. b) DSGVO und Dokumentation. +- **Organisatorisch:** Kontroll-/Überwachungsplan der DS-Funktion festlegen und durchführen. +- **Technisch:** Dokumentierte Audits/Kontrollen im DMS/Auditsystem. +- **Typische Nachweise:** Kontroll-/Auditplan, Prüfberichte, Maßnahmennachverfolgung. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion; Zeitaufwand. +- **AL-Filter:** AL2 | AL3 + +### 9.2.1-M5 — [MUSS] +**Anforderung:** Dokumentation des datenschutzrechtlichen Status und Bericht an die höchste Managementebene. +- **Organisatorisch:** Regelmäßige Datenschutzberichte an die Leitung etablieren. +- **Technisch:** Berichts-/Reportingablage. +- **Typische Nachweise:** Datenschutzberichte, Protokolle der Managementberichterstattung. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/Leitung. +- **AL-Filter:** AL2 | AL3 + +### 9.2.1-M6 — [MUSS] +**Anforderung:** Ausstattung mit ausreichenden Kapazitäten/Ressourcen (Qualifikation, Fortbildung, Fachliteratur, Koordinatoren). +- **Organisatorisch:** Ressourcen, Qualifikation, Fortbildungen und ggf. Datenschutzkoordinatoren je Bereich sicherstellen. +- **Technisch:** Zugang zu Fachliteratur/DS-Tools, Schulungssystem. +- **Typische Nachweise:** Fortbildungsnachweise, Ressourcen-/Budgetzuweisung, Koordinatorenbenennung. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** Budget Fortbildung/Personal. +- **AL-Filter:** AL2 | AL3 + +## Control 9.3.1 — Verzeichnis von Verarbeitungstätigkeiten + +### 9.3.1-M1 — [MUSS] +**Anforderung:** Verzeichnis von Verarbeitungstätigkeiten (Art. 30 Abs. 1/2 DSGVO) mit Prozessbeschreibung und Zuständigkeiten. +- **Organisatorisch:** VVT erstellen und pflegen; bei Auftragsverarbeitung nur auftragsgegenständliche Angaben; Prozess mit Zuständigkeiten und Aktualisierung definieren. +- **Technisch:** VVT-Tool/Vorlage mit Änderungshistorie; Verknüpfung zu TOM (aus IS-Fragebogen). +- **Typische Nachweise:** Gepflegtes VVT, Prozessbeschreibung, Aktualisierungsnachweise. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion; ggf. VVT-Tool. +- **AL-Filter:** AL2 | AL3 + +## Control 9.4.1 — Datenschutzfolgenabschätzung + +### 9.4.1-M1 — [MUSS] +**Anforderung:** Verarbeitungen, die eine DSFA benötigen, sind bekannt. +- **Organisatorisch:** Schwellwertanalyse/Kriterien zur DSFA-Pflicht festlegen und Verarbeitungen bewerten. +- **Technisch:** DSFA-Kennzeichnung im VVT/DS-Tool. +- **Typische Nachweise:** Schwellwertanalyse, Liste DSFA-pflichtiger Verarbeitungen. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +### 9.4.1-M2 — [MUSS] +**Anforderung:** DSFA werden durchgeführt; Verantwortlichkeiten/Unterstützung festgelegt und bekannt. +- **Organisatorisch:** DSFA-Prozess mit Rollen, Unterstützung und Freigabe definieren; DSFA durchführen. +- **Technisch:** DSFA-Methodik/Vorlage, Dokumentation im DS-Tool. +- **Typische Nachweise:** Durchgeführte DSFA, Prozessbeschreibung, Maßnahmenkatalog. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/Fachbereiche. +- **AL-Filter:** AL2 | AL3 + +## Control 9.5.1 — Management der Datenübermittlung + +### 9.5.1-M1 — [MUSS] +**Anforderung:** Prozesse/Arbeitsabläufe für Übermittlung (u. a. AV-Verträge Art. 28, Transferinstrumente, Zustimmung/Widerspruch bei Unterbeauftragung). +- **Organisatorisch:** Übermittlungsprozess mit Prüfung der Rechtsgrundlage, AV-Verträgen und Transferinstrumenten etablieren. +- **Technisch:** Vertrags-/Nachweismanagement mit Statusverfolgung. +- **Typische Nachweise:** AV-Verträge (Art. 28), SCC/TIA, Prozessbeschreibung, Zustimmungsnachweise. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/Recht. +- **AL-Filter:** AL2 | AL3 + +## Control 9.5.2 — Weitergabe vertraglicher Vereinbarungen an Unterauftragnehmer + +### 9.5.2-M1 — [MUSS] +**Anforderung:** Mit Auftraggebern vereinbarte vertragliche Vereinbarungen werden an Unterauftragsverarbeiter weitergegeben. +- **Organisatorisch:** Back-to-back-Weitergabe der Auftraggebervorgaben an Unterauftragnehmer sicherstellen. +- **Technisch:** Vertragsregister mit Verknüpfung Haupt-/Unterauftrag. +- **Typische Nachweise:** Unterauftrags-AV-Verträge, Vertragsregister. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/Einkauf. +- **AL-Filter:** AL2 | AL3 + +### 9.5.2-M2 — [MUSS] +**Anforderung:** Überprüfung der Einhaltung vertraglicher Vereinbarungen; aktuelle Ansprechpartner-Kontaktdaten verfügbar. +- **Organisatorisch:** Regelmäßige Kontrolle der Unterauftragnehmer und Pflege der Ansprechpartner-Kontaktdaten. +- **Technisch:** Lieferantenregister mit Kontrollstatus und Kontaktdaten. +- **Typische Nachweise:** Kontroll-/Auditnachweise, aktuelle Kontaktliste. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; R13 Lieferanten; VA-18. +- **Ressourcen:** DS-Funktion/Lieferantenmanagement. +- **AL-Filter:** AL2 | AL3 + +## Control 9.5.3 — Datenübermittlung in Drittländer + +### 9.5.3-M1 — [MUSS] +**Anforderung:** Drittlandübermittlungen sind bekannt und werden systematisch erfasst. +- **Organisatorisch:** Drittlandtransfers identifizieren und im VVT/Transferregister dokumentieren. +- **Technisch:** Kennzeichnung Drittlandtransfers im DS-Tool. +- **Typische Nachweise:** Transferübersicht, VVT-Einträge. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +### 9.5.3-M2 — [MUSS] +**Anforderung:** Geeignete Garantien (Kapitel V DSGVO, EuGH-Rechtsprechung, ggf. TIA) liegen vor. +- **Organisatorisch:** Transferinstrumente je Drittlandtransfer festlegen und TIA bei Relevanz durchführen. +- **Technisch:** Ablage SCC/Angemessenheitsbeschluss/TIA im Vertrags-/DS-Tool. +- **Typische Nachweise:** SCC/Garantien, TIA, Angemessenheitsnachweise. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/Recht. +- **AL-Filter:** AL2 | AL3 + +### 9.5.3-M3 — [MUSS] +**Anforderung:** Prüfung, ob Zustimmung des Verantwortlichen zu jeder Drittlandübermittlung einzuholen ist. +- **Organisatorisch:** Zustimmungsprüfung als Prozessschritt vor Drittlandtransfer verankern. +- **Technisch:** Freigabe-/Zustimmungsworkflow mit Dokumentation. +- **Typische Nachweise:** Zustimmungsnachweise, Prozessbeschreibung. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +## Control 9.6.1 — Betroffenenanfragen + +### 9.6.1-M1 — [MUSS] +**Anforderung:** Betroffenenanfragen werden fristgerecht bearbeitet; Verfahren zur Unterstützung des Verantwortlichen; Mitarbeiterschulung zur Weiterleitung. +- **Organisatorisch:** Prozess zur Erkennung, Weiterleitung und fristgerechten Bearbeitung von Betroffenenanfragen etablieren; Mitarbeiter schulen, unverzüglich den Verantwortlichen zu kontaktieren. +- **Technisch:** Ticket-/Fallmanagement mit Fristenüberwachung. +- **Typische Nachweise:** Prozessbeschreibung, Fallakten mit Fristen, Schulungsnachweise. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion; ggf. Fallmanagement-Tool. +- **AL-Filter:** AL2 | AL3 + +## Control 9.6.2 — Datenschutzvorfälle + +### 9.6.2-M1 — [MUSS] +**Anforderung:** Datenschutzvorfälle werden fristgerecht bearbeitet. +- **Organisatorisch:** Meldeprozess mit Fristen (u. a. 72-Stunden-Betrachtung) und Zuständigkeiten festlegen. +- **Technisch:** Vorfallmanagement mit Fristen-/Eskalationssteuerung. +- **Typische Nachweise:** Vorfallprozess, Vorfalldokumentation mit Fristen. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +### 9.6.2-M2 — [MUSS] +**Anforderung:** Maßnahmen aus IS 1.6.1 berücksichtigen auch Datenschutzvorfälle, alternativ eigener Notfallplan. +- **Organisatorisch:** Datenschutzvorfälle in das ISMS-Incident-Management integrieren oder eigenen DS-Notfallplan erstellen. +- **Technisch:** Gemeinsames/verknüpftes Incident-Tool. +- **Typische Nachweise:** Incident-Prozess mit DS-Bezug bzw. DS-Notfallplan. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/ISB. +- **AL-Filter:** AL2 | AL3 + +### 9.6.2-M3 — [MUSS] +**Anforderung:** Etablierte/dokumentierte Verfahren: unverzügliche Meldung an Verantwortlichen, Prozessdokumentation, Mitarbeiterschulung, Unterstützung des Verantwortlichen. +- **Organisatorisch:** Meldeweg zum Verantwortlichen, Dokumentationspflichten und Mitarbeiterschulung festlegen. +- **Technisch:** Meldeworkflow mit Benachrichtigung des Verantwortlichen. +- **Typische Nachweise:** Verfahrensbeschreibung, Meldenachweise, Schulungsnachweise. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +## Control 9.7.1 — Verpflichtung der Mitarbeiter auf Vertraulichkeit + +### 9.7.1-M1 — [MUSS] +**Anforderung:** Mitarbeiter mit Bezug zu personenbezogenen Daten werden dokumentiert zur Vertraulichkeit (auch über das Arbeitsverhältnis hinaus) und Datenschutz verpflichtet. +- **Organisatorisch:** Vertraulichkeits-/Datenschutzverpflichtung in Onboarding aufnehmen und dokumentieren. +- **Technisch:** HR-System mit Erfassung/Nachverfolgung der Verpflichtungen. +- **Typische Nachweise:** Unterzeichnete Verpflichtungserklärungen, Vollständigkeitsübersicht. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** HR/DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +## Control 9.7.2 — Schulung der Mitarbeiter zum Datenschutz + +### 9.7.2-M1 — [MUSS] +**Anforderung:** Mitarbeiter sind geschult/sensibilisiert; Abstufung nach Schutzbedarf; spezifische Unterweisung kritischer Bereiche (z. B. IT-Admins). +- **Organisatorisch:** Datenschutz-Schulungskonzept mit Abstufung nach Schutzbedarf und rollenspezifischen Inhalten festlegen. +- **Technisch:** LMS mit Pflichtzuweisung, rollenspezifischen Modulen und Fälligkeitssteuerung. +- **Typische Nachweise:** Schulungskonzept, Teilnahmenachweise, rollenspezifische Unterweisungen. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/HR; Schulungsbudget. +- **AL-Filter:** AL2 | AL3 + +## Control 9.8.1 — Umgang mit Weisungen in Auftragsverarbeitungsverhältnissen + +### 9.8.1-M1 — [MUSS] +**Anforderung:** Umgang mit Weisungen zur auftragsgegenständlichen Verarbeitung ist gewährleistet. +- **Organisatorisch:** Weisungsprozess mit definierten weisungsberechtigten/-empfangenden Stellen festlegen. +- **Technisch:** Dokumentierte Weisungsablage mit Nachverfolgung. +- **Typische Nachweise:** Weisungsprozess, dokumentierte Weisungen. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion. +- **AL-Filter:** AL2 | AL3 + +### 9.8.1-M2 — [MUSS] +**Anforderung:** Verfahren stellen sicher: Weisungen dokumentiert, umsetzbar (Berichtigen/Löschen), Daten nach Auftraggeber/Auftrag getrennt. +- **Organisatorisch:** Verfahren für Dokumentation, Umsetzung (Berichtigung/Löschung) und Mandantentrennung der Daten festlegen. +- **Technisch:** Mandantengetrennte Datenhaltung, Lösch-/Berichtigungsfunktionen, Protokollierung. +- **Typische Nachweise:** Verfahrensbeschreibung, Nachweis Datentrennung, Lösch-/Berichtigungsprotokolle. +- **Vorlage:** Richtlinie Datenschutz (D01) / R14 Compliance & Datenschutz; VA-18. +- **Ressourcen:** DS-Funktion/IT. +- **AL-Filter:** AL2 | AL3 diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C7_Rollen-Funktionstrennung.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C7_Rollen-Funktionstrennung.md new file mode 100644 index 0000000..3a6b286 --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C7_Rollen-Funktionstrennung.md @@ -0,0 +1,61 @@ +# C7 — ISMS-Soll-Rollenmodell + Funktionstrennung (+ Bestellungs-Vorlage) + +> **Schaltet frei:** A4 (ISMS-Rollen & Funktionstrennung, Schritt 3). **Grundlage:** `variables.schema.json` (`ROLE_*`), Richtlinie `R01_ISMS-Organisation-und-Rollen`. + +## 1. Soll-Rollenmodell + +| Rolle | Variable | Kernverantwortung | Besetzung | +|---|---|---|---| +| Oberste Leitung | `ROLE_MANAGEMENT` | Gesamtverantwortung ISMS, Ressourcen, Freigabe von Leitlinie/Richtlinien, Managementbewertung | intern (GF) | +| Informationssicherheitsbeauftragte(r) | `ROLE_ISB` | Aufbau/Pflege/Weiterentwicklung ISMS, Beratung der Leitung, Risikomanagement, Audits, Meldeweg; berichtet direkt an die Leitung | intern **oder** extern | +| IT-Leitung / IT-Verantwortung | `ROLE_IT_LEAD` | Betrieb, technische Umsetzung der Maßnahmen | intern oder extern (Dienstleister) | +| Personalleitung | `ROLE_HR_LEAD` | Personalsicherheit, On-/Offboarding, Awareness | intern | +| Datenschutzbeauftragte(r) | `ROLE_DPO` | Datenschutz-Compliance (bei Verarbeitung personenbezogener Daten) | intern oder extern | + +Bezug: Controls 1.2.1/1.2.2 (Organisation der IS), 2.1.x (Personal), 7.1.2 (Datenschutz). Rollen-Variablen befüllen Platzhalter in allen Vorlagen (Verantwortlich/Freigabe). + +## 2. Funktionstrennungs-Regeln (Prüfung im Wizard) + +| Regel-ID | Bedingung | Ergebnis | Begründung | +|---|---|---|---| +| FT-01 | `ROLE_ISB` = `ROLE_IT_LEAD` (dieselbe Person, beide intern) | **Konflikt** → Hinweis + Aufgabe | ISB muss die IT unabhängig überwachen können; Selbstkontrolle unzulässig | +| FT-02 | `ROLE_ISB` intern **und** direkt der IT-Leitung unterstellt | **Konflikt (schwach)** → Hinweis | Weisungsunabhängigkeit/Berichtsweg an Leitung gefährdet | +| FT-03 | `ROLE_ISB` = `ROLE_MANAGEMENT` | **Konflikt** → Hinweis + Aufgabe | Leitung kann eigene ISMS-Verantwortung nicht selbst überwachen | +| FT-04 | `ROLE_ISB` nicht benannt | **Lücke** → Aufgabe „ISB bestellen" (Control 1.2.2) | ISB ist Muss-Anforderung | +| FT-05 | `ROLE_DPO` fehlt trotz `FLAG_PERSONAL_DATA` | **Lücke** → Aufgabe „DSB benennen/prüfen" | Datenschutz-Organisation erforderlich | +| FT-06 | Antragsteller = Genehmiger von Zugriffsrechten (aus IAM-Daten) | **Konflikt** → Hinweis | Vier-Augen bei Berechtigungsvergabe (Control 4.2.1) | + +**Kompensierende Kontrollen** (wenn Trennung z. B. bei Kleinorganisation nicht möglich): externer ISB (GEFIM-Modell), Vier-Augen mit der Leitung, dokumentierte Ausnahmegenehmigung + verstärkte Protokollierung. Der Wizard bietet bei Konflikt „Trennung herstellen" **oder** „kompensierende Kontrolle dokumentieren" (→ Aufgabe bzw. Nachweis). + +## 3. Bestellungs-/Ernennungs-Vorlage (Paket-Stil) + +Neue Vorlage `VA-00_ISB-Bestellung.md` bzw. Textbaustein in `R01`, mit Platzhaltern und Ankern: + +```markdown +# Bestellung Informationssicherheitsbeauftragte(r) + +| Feld | Wert | +|------|------| +| Organisation | {{ORG_NAME}} | +| Bestellte Person / Funktion | {{ROLE_ISB}} | +| Bestellt durch | {{ROLE_MANAGEMENT}} | +| Besetzung | {{#if FLAG_ISB_EXTERNAL}}extern (Dienstleistervertrag){{/if}}{{#if FLAG_ISB_INTERNAL}}intern{{/if}} | +| Version / Datum / Status | {{DOC_VERSION}} / {{DOC_DATE}} / {{DOC_STATUS}} | + +<!-- REQ 1.2.2-M1 --> +Die Organisation {{ORG_NAME}} bestellt {{ROLE_ISB}} mit Wirkung zum {{DOC_DATE}} zum/zur Informationssicherheitsbeauftragten. + +## Aufgaben und Befugnisse +- Aufbau, Pflege und Weiterentwicklung des ISMS gemäß VDA ISA. +- Beratung der Leitung; jährliche Überprüfung von Richtlinien und Wirksamkeit. +- Koordination von Risikomanagement, Schulungen, Audits, Maßnahmen. +- Melde-/Eskalationsrecht direkt an {{ROLE_MANAGEMENT}}; Zugang zu relevanten Informationen/Systemen. + +## Freigabe +| Rolle | Name | Datum, Unterschrift | +|-------|------|---------------------| +| Leitung | {{ROLE_MANAGEMENT}} | | +| ISB | {{ROLE_ISB}} | | +``` + +Neue Flags bei Bedarf in `variables.schema.json`: `FLAG_ISB_EXTERNAL` / `FLAG_ISB_INTERNAL` (aus Q-ROLE-02). Nach Anlage `_verify.py` → **OK**. diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C8_Priorisierung-Gap.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C8_Priorisierung-Gap.md new file mode 100644 index 0000000..741f424 --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C8_Priorisierung-Gap.md @@ -0,0 +1,37 @@ +# C8 — Priorisierungslogik Gap + Quick-Wins + +> **Schaltet frei:** A8 (Gap-Konsolidierung, Schritt 8). **Grundlage:** Ergebnisse aus Schritt 6 (Risiko) und 7 (Control-Assessment), Aufgaben-Modul. + +## 1. Prioritätsregeln (deterministisch) + +Priorität eines offenen Punkts = höchste zutreffende Regel: + +| Priorität | Bedingung | +|---|---| +| **Hoch** | Offene **MUSS**-Anforderung (Reifegrad < 2) · **oder** offene AL3-Zusatzanforderung (`HOCH`/`SEHR HOCH`) bei entsprechendem Schutzbedarf · **oder** Behandlungsmaßnahme zu einem Risiko oberhalb der Akzeptanzlinie · **oder** fehlende Muss-Rolle/Funktionstrennungs-Konflikt (C7 FT-01/03/04) | +| **Mittel** | Offene **SOLL**-Anforderung · Reifegrad = 2 aber unter Zielreifegrad 3 · Nachweis vorhanden aber nicht validiert · Dokument im Entwurf/nur als Vorlage | +| **Niedrig** | Redaktioneller/formaler Punkt · Optimierung ohne Reifegrad-Wirkung · Nachweis nur zu aktualisieren | + +Zusatzgewichtung (Sortierung innerhalb gleicher Priorität): (1) Anzahl betroffener Controls, (2) Risikohöhe des verknüpften Risikos, (3) Aufwand aufsteigend (Quick-Wins zuerst). + +## 2. Deduplizierung + +Offene Punkte aus Schritt 6 und 7 werden zusammengeführt. Dedup-Schlüssel = (Control + Teilanforderungs-ID) bzw. (verknüpfte Maßnahme/Aufgabe). Regeln: + +- Gleiche Teilanforderung aus mehreren Quellen → **ein** Punkt, höchste Priorität gewinnt, Quellen werden verknüpft. +- Ein offener Punkt, für den bereits eine Aufgabe existiert → keine neue Aufgabe, bestehende verknüpfen. +- Risiko-Maßnahme und Control-Gap, die dieselbe Maßnahme adressieren (z. B. „Patchmanagement einführen" für Risiko R-OPS-03 und Controls 5.2.3/5.2.5) → zusammenführen, alle Bezüge an die eine Aufgabe hängen. + +## 3. Quick-Wins + +Ein offener Punkt ist **Quick-Win**, wenn: geringer Aufwand (organisatorisch/redaktionell, kein Tool-/Budgetbedarf) **und** Reifegrad-Wirkung ≥ +1 auf mindestens ein Control **und** keine Abhängigkeit von anderer offener Maßnahme. Typische Quick-Wins: Freigabe/Validierung eines bereits erstellten Dokuments, Befüllen einer vorhandenen Vorlage (Konten-Review, Rezertifizierung), Rollen-/Funktionstrennungs-Dokumentation, Redaktionslücken schließen. Der Wizard hebt Quick-Wins im Maßnahmenplan gesondert hervor (Reihenfolge-Empfehlung „erst Quick-Wins, dann Hoch-Aufwand"). + +## 4. Beispiel-Priorisierung + +| Offener Punkt | Regel | Priorität | Quick-Win? | +|---|---|---|---| +| Kein Patchmanagement (Controls 5.2.3/5.2.5, Risiko R-OPS-03) | MUSS < 2 + Risiko | Hoch | nein (Tool) | +| Restore-Test nicht durchgeführt (5.2.9, BL-OPS-06) | MUSS-Nachweis fehlt | Hoch | ja (organisatorisch) | +| ISB = IT-Verantwortung (FT-01) | Funktionstrennungs-Konflikt | Hoch | teils (extern/kompensieren) | +| SOLL Berechtigungs-Review nur als Vorlage (4.2.1) | SOLL, nicht validiert | Mittel | ja | +| Zonenbezeichnung inkonsistent (3.1.1) | redaktionell | Niedrig | ja | diff --git a/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C9_Auswertung-Export.md b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C9_Auswertung-Export.md new file mode 100644 index 0000000..4ba029c --- /dev/null +++ b/docs/wizard-uebergabe/02_Fachcontent_C1-C9/C9_Auswertung-Export.md @@ -0,0 +1,49 @@ +# C9 — Auswertungs-/Interpretationstexte + Export-Layout + +> **Schaltet frei:** B7 (Assessment-Readiness & Export, Schritt 9). **Grundlage:** validierte Control-Bewertungen (Schritt 7), Gap-/Maßnahmenliste (Schritt 8), Validierungsstatus (A3). + +## 1. Reifegrad-Dashboard — Interpretationstexte + +Aggregation je Kapitel und gesamt (Durchschnitt der Control-Reifegrade, „unbestätigt" zählt nicht als erfüllt). Textbänder nach Gesamtreifegrad: + +| Reifegrad (Ø) | Band | Interpretationstext | +|---|---|---| +| < 1,5 | Aufbau | „Das ISMS befindet sich im Aufbau. Wesentliche Richtlinien/Verfahren sind noch zu erstellen oder freizugeben. Fokus: Muss-Anforderungen und Grundstruktur." | +| 1,5 – < 2,5 | Etabliert im Aufbau | „Grundlegende Prozesse sind vorhanden und teils dokumentiert. Für Assessment-Reife fehlen v. a. Nachweise der gelebten Anwendung und Validierungen." | +| 2,5 – < 3,0 | Assessment-nah | „Das ISMS ist überwiegend etabliert. Wenige offene Punkte und Nachweise trennen von der Assessment-Reife (AL-Ziel). Fokus: Hoch-Punkte schließen, Wirksamkeitsnachweise ergänzen." | +| = 3,0 | Assessment-reif | „Die bewerteten Controls erfüllen den Zielreifegrad. Empfehlung: Stichprobenvalidierung und Aktualität der Nachweise vor dem Assessment sicherstellen." | + +Zusätzliche Kennzahlen: Anteil bestätigter (validierter) Controls, Anzahl offener Punkte je Priorität, Abdeckung je Prüfziel, „höchstes erreichbares Ergebnis" = Zielreifegrad. + +## 2. Empfohlene nächste Schritte (dynamisch) + +Regelbasiert eingeblendet: + +- Offene **Hoch**-Punkte vorhanden → „Vor dem Assessment zwingend: die N Hoch-Punkte im Maßnahmenplan abarbeiten (siehe Aufgaben)." +- Unvalidierte Objekte vorhanden → „X Objekte warten auf Validierung durch ISB/Berater — bis dahin als ‚unbestätigt' gewertet." +- Prüfziel Prototypenschutz aktiv & 8.x < Ziel → „Prototypenspezifische Nachweise ergänzen (physische Schutzmaßnahmen, Zutritt, Transport)." +- Nachweis-Upload-Iteration noch offen → „Operative Nachweise (Screenshots/Protokolle) in der Folgeiteration hochladen." + +## 3. VDA-ISA-Katalog-Export — Layout + +**Struktur (je Prüfziel ein Tabellenblatt/Abschnitt, Reihenfolge Informationssicherheit → Prototypenschutz → Datenschutz):** + +| Feld | Inhalt | Quelle | +|---|---|---| +| Control-ID | z. B. 4.1.2 | Katalog | +| Kontrollfrage / Ziel | aus Katalog | Katalog | +| Reifegrad | 0–3 (bestätigt) bzw. „na" | Schritt 7 | +| Status | bestätigt / unbestätigt | A3-Validierung | +| Umsetzungsbeschreibung | je Teilanforderung: **Anforderung (fett)** + Umsetzung (normal), Reihenfolge MUSS→SOLL→HOCH→SEHR HOCH | Schritt 7 + Vorlagen-IMPL | +| Belege | verknüpfte Dokumente/Verfahren/Risiken/Assets | Schritt 4–7 | +| Offene Punkte | je Control aus Gap-Liste | Schritt 8 | + +**Darstellungsregeln:** Anforderungstext im Originalwortlaut, **fett**; Umsetzung normal darunter mit Quellenangabe (Dokument, Version/Stand, Kapitel) — konsistent zur bisherigen Ausarbeitung. „Unbestätigt" sichtbar markieren (z. B. Kennzeichnung/Farbe). Ergänzungshinweise/offene Punkte **nicht** im Katalog, sondern in der separaten Maßnahmen-/Schwachstellenliste. + +**Exportformate:** XLSX (VDA-ISA-Katalogsicht + Ergebnisblatt mit Reifegrad-Kennzahlen), zusätzlich DOCX/PDF für Management-Zusammenfassung. Der Export koppelt an den bestehenden DOCX/PDF-Export der App. + +## 4. Zusatzartefakte im Export + +- **Maßnahmenplan** (aus C8): priorisierte offene Punkte + verknüpfte Aufgaben, Quick-Wins hervorgehoben. +- **Nachweisregister** (aus `Nachweisregister_zentral.md`): je Anforderung der zugeordnete Nachweis/Status. +- **Management-Zusammenfassung**: Stärken, Reifegrad-Überblick, Hoch-Punkte, empfohlene Schritte vor dem Assessment. diff --git a/docs/wizard-uebergabe/03_Referenz/Onboarding_Wizard_Fahrplan_Detail.md b/docs/wizard-uebergabe/03_Referenz/Onboarding_Wizard_Fahrplan_Detail.md new file mode 100644 index 0000000..3e282c3 --- /dev/null +++ b/docs/wizard-uebergabe/03_Referenz/Onboarding_Wizard_Fahrplan_Detail.md @@ -0,0 +1,233 @@ +# Onboarding-Wizard ISMS – Detaillierter Fahrplan & Entwickler-Handlungsanweisung + +**Produkt:** ISMS-Applikation – Onboarding-Wizard +**Fokus der ersten Ausbaustufe:** TISAX / VDA ISA +**Ziel (North Star):** Assessment-Readiness – am Ende des Wizards liegt ein vorausgefüllter VDA-ISA-Katalog inkl. Reifegrad-Ersteinschätzung und Maßnahmenplan vor. +**Modus:** Kunde bearbeitet eigenständig; ISB oder externer Berater (falls gebucht) validiert an definierten Gates. +**Tailoring:** Template- und regelbasiert; eigene Richtlinien optional hochladbar; die mitgelieferten Vorlagen sind optional. +**Status:** Detailausarbeitung zur Verifizierung vor der technischen Umsetzung. + +--- + +## 1. Lesehinweis & Konventionen + +Dieses Dokument beschreibt je Wizard-Schritt: Zweck, Ein-/Ausgaben, Verarbeitungslogik, erzeugte Objekte, kontextsensitive Umsetzungshinweise, Aufgaben-Trigger, Validierung, benötigte Entwicklungs-Ressourcen und Akzeptanzkriterien. Es ist eine fachliche Handlungsanweisung, keine technische Spezifikation – Technologiewahl, konkrete Schemata und UI-Design folgen in der Umsetzung. + +**Aufwands-/Ressourcengröße (T-Shirt):** S = klein, M = mittel, L = groß. Bezieht sich auf den Entwicklungsaufwand des jeweiligen Bausteins, nicht auf die Kundenlaufzeit. + +**Rollen im Wizard** + +| Rolle | Aufgabe | +|---|---| +| Bearbeiter (Kunde) | Durchläuft die Schritte, gibt Fakten ein, wählt/erstellt Dokumente, bewertet Controls und Risiken | +| Validierer (ISB intern oder externer Berater) | Prüft und gibt Module/Objekte frei; ohne Freigabe fließt Inhalt als „unbestätigt" in die Auswertung | +| Systemadministrator (Vorbedingung) | Richtet Mandant, Nutzer und Rollen ein – **außerhalb** des Wizards | + +--- + +## 2. Querschnittsmechaniken (gelten in allen Schritten) + +Diese vier Mechaniken sind kein eigener Schritt, sondern durchziehen den gesamten Wizard und sollten früh als wiederverwendbare Bausteine gebaut werden. + +### 2.1 Validierungs-Workflow + +Jedes bearbeitbare Objekt (Modul, Richtlinie, Risiko, Control-Bewertung) trägt einen Status: `offen → in Bearbeitung → zur Validierung → validiert` (bzw. `zurückgewiesen` mit Kommentar). Nur validierte Inhalte zählen in der Assessment-Readiness-Auswertung als „bestätigt". Der Validierer erhält je Objekt Kontext, Kommentar- und Freigabefunktion. Ist kein externer Berater gebucht, übernimmt der interne ISB die Validierung. +**Ressourcen:** Backend (Statusmodell, Rechte) M · Frontend (Review-Ansicht, Kommentare) M. + +### 2.2 Umsetzungshinweise („So setzen Sie diese Anforderung um") + +An jeder VDA-ISA-Teilanforderung (und optional an Risiken/Templates) hängt redaktioneller Hinweis-Content, der bei der Bearbeitung kontextsensitiv eingeblendet wird. Ein Hinweis umfasst typischerweise: organisatorische Umsetzungsoption, technische Umsetzungsoption, typische Nachweise, geeignete Vorlage (Verweis) und eine **Ressourcenindikation** (Tool/Personal/Budget/Zeit). Die Einblendung wird über Scope und Antworten gefiltert (z. B. nur AL3-relevante Hinweise). Hinweise sind Wissensinhalt, keine trackbare Aufgabe – führt ein Hinweis zu einer umzusetzenden Maßnahme, entsteht daraus eine Aufgabe (siehe 2.3). +**Ressourcen:** Fachredaktion/ISMS-SME (Content-Pflege) L · Backend (Hinweis-Datenmodell, Filter) S · Frontend (Inline-Panel) S. + +### 2.3 Maßnahmen → Aufgaben-Modul + +Ergibt sich bei der Bearbeitung eine umzusetzende Maßnahme (z. B. „Patchmanagement-Tool einführen", „Berechtigungs-Review etablieren", „Notfallübung durchführen"), wird daraus eine **Aufgabe im Aufgaben-Modul** erzeugt – automatisch vorgeschlagen und vom Bearbeiter bestätigt. Trigger-Punkte: Richtlinie „später erstellen" (Schritt 4), Risikobehandlung (Schritt 6), Control-Lücke/Reifegrad < Ziel (Schritt 7), Gap-Liste (Schritt 8), Zurückweisung durch Validierer. + +**Aufgaben-Objekt (Felder):** Titel, Beschreibung, Typ (`Dokument erstellen` / `Nachweis liefern` / `technische Maßnahme` / `organisatorische Maßnahme`), Verantwortlicher, Fälligkeit, Priorität, Status, Verknüpfung (Control / Risiko / Dokument / Asset), **benötigte Ressourcen** (Tool, Budget, Personal, Zeit), Herkunft (auslösender Schritt). Die Ressourcenindikation stammt aus dem Umsetzungshinweis und ist editierbar. + +*Beispiel:* Control 5.2.3/5.2.5 unzureichend → Hinweis „technische Umsetzung: zentrales Patchmanagement" → Aufgabe „Patchmanagement-Tool auswählen und einführen", Typ `technische Maßnahme`, verknüpft mit 5.2.3 und 5.2.5, Ressourcen: Tool-Lizenz + IT-Personal ca. X PT, Priorität Hoch. +**Ressourcen:** Backend (Task-Generierung, Verknüpfungen, API zum Aufgaben-Modul) M · Frontend (Vorschlag/Bestätigung, Ressourcenfelder) M. Voraussetzung: Aufgaben-Modul der App existiert bzw. bietet eine Schnittstelle. + +### 2.4 Audit-Trail & Versionierung + +Jede Eingabe, Statusänderung und Freigabe wird protokolliert (wer/wann/was). Templates, Katalog und Risikokatalog sind versioniert; Kundendokumente referenzieren die genutzte Template-Version. +**Ressourcen:** Backend (Event-Log, Versionierung) M. + +--- + +## 3. Fachliche Bausteine / Datenobjekte (Fundament) + +| Baustein | Inhalt | Ressourcen | +|---|---|---| +| Control-Katalog VDA ISA | Prüfziele, Assessment-Level, je Control die Muss-/Soll-/Zusatzanforderungen als einzeln adressierbare Teilanforderungen | SME (Datenpflege) M · Backend (Import/Modell) S | +| Template-Bibliothek (optional) | Richtlinien-/VA-Vorlagen mit Platzhaltern, optionalen Bausteinen und Control-Verknüpfung | SME/Content L · Backend S | +| Upload-Pfad eigene Dokumente | Upload + Zuordnung „welche Controls belegt dieses Dokument" | Backend S · Frontend S | +| Fakten-/Fragemodell | Antwortobjekte zu Organisation, IT, Dienstleistern, Prozessen; wiederverwendbar | SME (Fragebogen) M · Backend M | +| Risiko-Katalog | Standard- und VDA-geforderte Risiken, vordefiniert und erweiterbar; Verknüpfung zu Controls/Assets | SME L · Backend M | +| Regel-/Mapping-Layer | Antwort → Platzhalter, Klausel-Ein/Ausblendung, betroffene Controls/Assets/Risiken | Backend (Regel-Engine) L | +| Reifegrad-/Gap-Engine | Reifegrad-Ersteinschätzung + offene Punkte je Control | Backend M · SME (Logik) M | + +--- + +## 4. Die Schritte im Detail + +> Vorbedingung (außerhalb des Wizards): technisches Onboarding – Mandant, Nutzer, Rollen eingerichtet. + +### Schritt 1 – Scoping + +- **Zweck:** Prüfziele, Assessment-Level (AL2/AL3), Standorte und Geltungsbereich festlegen. Dies steuert, welche Controls, Templates und Risiken im weiteren Verlauf überhaupt relevant sind. +- **Eingaben:** Prüfziele (Info-Sicherheit, Prototypenschutz, Datenschutz), Assessment-Level, Standort(e), organisatorischer/technischer Geltungsbereich, Ausschlüsse. +- **Verarbeitung & Regeln:** Aktiviert/deaktiviert Control-Set und Template-Set; z. B. Prototypenschutz nur bei entsprechendem Prüfziel, AL3 schaltet Zusatzanforderungen „sehr hoher Schutzbedarf" frei. +- **Erzeugte Objekte:** Scope-Objekt; gefiltertes Control-Set als Arbeitsgrundlage. +- **Umsetzungshinweise:** Erläuterung der Prüfziele und Level (Entscheidungshilfe AL2 vs. AL3), typische Scope-Formulierungen. +- **Aufgaben-Trigger:** i. d. R. keine. +- **Validierung:** Scope wird durch ISB/Berater bestätigt (Fundament für alles Weitere). +- **Ressourcen (Entwicklung):** Frontend (Scoping-UI) S · Backend (Scope-Filterlogik) M · SME (Scope-Regeln) S. +- **Akzeptanzkriterien:** Geänderter Scope filtert nachgelagerte Schritte korrekt; nicht relevante Controls/Templates sind ausgeblendet. + +### Schritt 2 – Kontextaufnahme (Gegebenheiten) + +- **Zweck:** Die tatsächlichen Gegebenheiten der Organisation als Faktenbasis erheben, die Platzhalter befüllt und Regeln aktiviert. +- **Eingaben:** Geführter Fragebogen – Unternehmensdaten, Organisationsstruktur, IT-Landschaft (Systeme, Cloud, Netzwerke), eingesetzte Dienstleister, relevante Prozesse, grundlegender Schutzbedarf. +- **Verarbeitung & Regeln:** Antworten werden als wiederverwendbare Faktenobjekte gespeichert und mit Platzhaltern, Klauselregeln, Controls, Assets und Risiken verknüpft. Bedingte Fragen (nur anzeigen, wenn relevant). +- **Erzeugte Objekte:** Faktenprofil der Organisation. +- **Umsetzungshinweise:** Erläuterung, warum eine Angabe gebraucht wird und wie sie sich auf Dokumente/Bewertung auswirkt. +- **Aufgaben-Trigger:** Fehlende Grundvoraussetzung erkennbar (z. B. „kein Inventar vorhanden") → optionale Aufgabe. +- **Validierung:** Plausibilitätsprüfung durch ISB/Berater. +- **Ressourcen (Entwicklung):** Frontend (dynamischer Fragebogen) M · Backend (Faktenmodell, bedingte Logik) M · SME (Fragenkatalog) M. +- **Akzeptanzkriterien:** Antworten sind wiederverwendbar; eine Änderung propagiert sichtbar in abhängige Objekte. + +### Schritt 3 – Rollen & Verantwortlichkeiten + +- **Zweck:** ISMS-Rollen festlegen (Geschäftsführung, ISB/DSB, IT-Verantwortung), inkl. Funktionstrennung. +- **Eingaben:** Personen/Funktionen je Rolle; intern/extern; Weisungs-/Berichtswege. +- **Verarbeitung & Regeln:** Prüft auf Funktionstrennung (z. B. ISB ≠ IT-Verantwortung); befüllt Rollen-Platzhalter in Dokumenten (Bestellungen/Ernennungen). +- **Erzeugte Objekte:** Rollenmodell; Dokumente wie ISB-Bestellung (aus Vorlage, optional). +- **Umsetzungshinweise:** Anforderungen an ISB-Qualifikation, externe vs. interne Besetzung, typische Nachweise. +- **Aufgaben-Trigger:** Fehlende ISB-Bestellung / fehlende Funktionstrennung → Aufgabe (organisatorische Maßnahme). +- **Validierung:** Freigabe des Rollenmodells. +- **Ressourcen (Entwicklung):** Frontend S · Backend (Rollenmodell, Regelprüfung) M · SME S. +- **Akzeptanzkriterien:** Funktionstrennungs-Konflikt wird erkannt und als Hinweis/Aufgabe ausgewiesen. + +### Schritt 4 – Richtlinien & Verfahrensanweisungen + +- **Zweck:** Für jeden relevanten Themenbereich die belegenden Dokumente bereitstellen – flexibel in der Quelle. +- **Eingaben:** Je Themenbereich Auswahl einer von drei Optionen: + (a) mitgelieferte Vorlage tailoren (Platzhalter aus Fakten befüllt, nicht zutreffende Klauseln ausgeblendet), + (b) eigene Richtlinie hochladen und den abgedeckten Controls zuordnen, + (c) als offen markieren / später erstellen. +- **Verarbeitung & Regeln:** (a) Template-Engine erzeugt kundenspezifisches Dokument aus Faktenprofil + Regeln; (b) Upload wird gespeichert und über Control-Mapping in die Nachweislage aufgenommen; (c) erzeugt Aufgabe. +- **Erzeugte Objekte:** Dokumenten-Set (generiert oder hochgeladen) mit Control-Verknüpfung und Versionsbezug. +- **Umsetzungshinweise:** Was die jeweilige Richtlinie mindestens enthalten muss (VDA-ISA-Bezug); Formulierungsbausteine. +- **Aufgaben-Trigger:** Option (c) „später erstellen" → Aufgabe `Dokument erstellen`; hochgeladenes Dokument ohne vollständige Control-Abdeckung → Hinweis/Aufgabe. +- **Validierung:** Freigabe je Dokument (Objekt-Ebene). +- **Ressourcen (Entwicklung):** Backend (Template-Engine, Platzhalter/Regeln, Rendering) L · Frontend (Auswahl, Editor/Vorschau, Upload) L · SME/Content (Vorlagen mit Regeln auszeichnen) L. +- **Akzeptanzkriterien:** Generiertes Dokument enthält keine unaufgelösten Platzhalter und keine nicht zutreffenden Klauseln; hochgeladenes Dokument ist Controls zugeordnet. + +### Schritt 5 – Werte-/Assetinventar (Grundstock) + +- **Zweck:** Die für Scope und Schutzbedarf nötigen Informationswerte/Assets erfassen. +- **Eingaben:** Assets (Kategorie, Eigentümer, Schutzziele C/I/A, Schutzbedarf, Standort/Verknüpfung). +- **Verarbeitung & Regeln:** Assets werden Risiken (Schritt 6) und Controls zugeordnet; Schutzbedarf steuert die AL3-Relevanz von Zusatzanforderungen. +- **Erzeugte Objekte:** Assetinventar (Grundstock). +- **Umsetzungshinweise:** Wie man Werte identifiziert und Schutzbedarf herleitet; Beispielkategorien. +- **Aufgaben-Trigger:** Unvollständiges Inventar / fehlender Eigentümer → Aufgabe. +- **Validierung:** Freigabe des Inventars. +- **Ressourcen (Entwicklung):** Frontend (Inventar-CRUD, Import) M · Backend (Assetmodell, Verknüpfungen) M · SME S. +- **Akzeptanzkriterien:** Jedes Asset hat Eigentümer und Schutzbedarf; Verknüpfung zu Risiken/Controls möglich. + +### Schritt 6 – Risikomanagement + +- **Zweck:** Risiken systematisch erfassen, bewerten und behandeln – auf Basis eines Katalogs mit Standard- und VDA-geforderten Risiken. +- **Eingaben:** Auswahl aus Risiko-Katalog (Standard/VDA) + eigene Ergänzungen; Bewertung (Eintrittswahrscheinlichkeit/Schadensausmaß); Behandlungsentscheidung. +- **Verarbeitung & Regeln:** Risiken werden mit Assets und Controls verknüpft; Bewertungsmethodik (Skalen, Akzeptanzlinie) wird angewendet; Behandlungsoptionen (reduzieren/übertragen/vermeiden/akzeptieren) mit Maßnahmenableitung. +- **Erzeugte Objekte:** Risikoregister; Behandlungsmaßnahmen. +- **Umsetzungshinweise:** Vorschlag typischer Maßnahmen je Risiko; Erläuterung der Bewertungsmethodik. +- **Aufgaben-Trigger:** Jede Behandlungsmaßnahme, die Umsetzung erfordert → Aufgabe (technisch/organisatorisch), verknüpft mit Risiko und Control (z. B. Risiko „Schadsoftware" → Aufgabe „Endpoint-/Patchmanagement einführen"). +- **Validierung:** Freigabe des Risikoregisters bzw. je Risiko. +- **Ressourcen (Entwicklung):** Backend (Risikomodell, Bewertungslogik, Katalog) L · Frontend (Register, Matrix, Bewertung) L · SME (Risiko-Katalog + Standardmaßnahmen) L. +- **Akzeptanzkriterien:** VDA-geforderte Risiken sind auswählbar; jedes inakzeptable Risiko hat eine Behandlung; Maßnahmen erzeugen Aufgaben. + +### Schritt 7 – Control-Zuordnung & Reifegrad + +- **Zweck:** Je relevantem VDA-ISA-Control die Umsetzung bewerten und Reifegrad einschätzen. +- **Eingaben:** Je Control: Verknüpfung der belegenden Dokumente/Risiken/Assets; geführte Reifegrad-Selbsteinschätzung; ggf. Kurzbeschreibung. +- **Verarbeitung & Regeln:** Reifegrad-/Gap-Engine schlägt auf Basis vorhandener Belege einen Reifegrad vor; offene Teilanforderungen werden markiert. +- **Erzeugte Objekte:** Control-Bewertung (Reifegrad, Belege, offene Punkte) – die Rohdaten des späteren VDA-ISA-Katalogs. +- **Umsetzungshinweise:** Pro Teilanforderung „So setzen Sie das um" (organisatorisch/technisch, Nachweise, passende Vorlage, Ressourcenbedarf). +- **Aufgaben-Trigger:** Reifegrad unter Ziel / offene Teilanforderung → Aufgabe (Dokument, Nachweis, technische oder organisatorische Maßnahme). +- **Validierung:** Freigabe der Control-Bewertung durch ISB/Berater. +- **Ressourcen (Entwicklung):** Backend (Scoring/Gap-Logik, Verknüpfungen) L · Frontend (Control-Ansicht, Belege, Reifegrad) L · SME (Reifegrad-Logik, Hinweis-Content) L. +- **Akzeptanzkriterien:** Jede relevante Teilanforderung ist adressiert; Reifegradvorschlag ist nachvollziehbar an Belege gekoppelt. + +### Schritt 8 – Gap- & Maßnahmenableitung + +- **Zweck:** Offene Punkte aus Controls und Risikobehandlung zu einer priorisierten Maßnahmenliste zusammenführen. +- **Eingaben:** Ergebnisse aus Schritt 6 und 7; bestehende Aufgaben. +- **Verarbeitung & Regeln:** Deduplizierung, Priorisierung (Muss-/AL3-kritisch = hoch), Konsolidierung zu einer Gesamtsicht; Abgleich mit dem Aufgaben-Modul. +- **Erzeugte Objekte:** Konsolidierte Maßnahmen-/Gap-Liste (verknüpft mit Aufgaben). +- **Umsetzungshinweise:** Priorisierungslogik erläutert; Quick-Wins hervorgehoben. +- **Aufgaben-Trigger:** Jeder offene Punkt ohne bestehende Aufgabe → Aufgabe. +- **Validierung:** Freigabe der Maßnahmenliste. +- **Ressourcen (Entwicklung):** Backend (Aggregation/Dedup/Priorisierung) M · Frontend (Listenansicht, Filter) M. +- **Akzeptanzkriterien:** Keine Dopplungen; jeder offene Punkt hat Priorität und – wo Umsetzung nötig – eine Aufgabe. + +### Schritt 9 – Assessment-Readiness-Auswertung + +- **Zweck:** Das Gesamtergebnis darstellen: vorausgefüllter VDA-ISA-Katalog, Reifegrad-Dashboard, Maßnahmenplan. +- **Eingaben:** Alle validierten Objekte. +- **Verarbeitung & Regeln:** Aggregation der Reifegrade je Kapitel/gesamt; „bestätigt vs. unbestätigt" nach Validierungsstatus; Export. +- **Erzeugte Objekte:** VDA-ISA-Katalog-Sicht/Export; Reifegrad-Dashboard; Maßnahmenplan. +- **Umsetzungshinweise:** Interpretation der Auswertung; empfohlene nächste Schritte vor dem Assessment. +- **Aufgaben-Trigger:** Aus offenen Hoch-Punkten ableitbar (bereits in Schritt 8 erzeugt). +- **Validierung:** Gesamtfreigabe/Abschluss durch ISB/Berater. +- **Ressourcen (Entwicklung):** Backend (Aggregation, Export) M · Frontend (Dashboard, Katalogansicht) L · SME (Auswertungslogik) M. +- **Akzeptanzkriterien:** Kennzahlen stimmen mit den Einzelbewertungen überein; Export ist vollständig und nachvollziehbar. + +--- + +## 5. Entwicklungs-Fahrplan (Meilensteine mit Ressourcen) + +| Meilenstein | Inhalt | Schritte | Kern-Ressourcen | Größe | +|---|---|---|---|---| +| M1 Fundament | Datenmodell + Import Control-Katalog VDA ISA | – | Backend, SME | M | +| M2 Frage-Engine | Scoping + Kontext + Rollen | 1–3 | Backend, Frontend, SME | L | +| M3 Richtlinien-Modul | Template-Engine + Upload/Control-Mapping | 4 | Backend, Frontend, Content-SME | L | +| M4 Asset- & Risiko-Modul | Assetinventar + Risiko-Katalog + Bewertung | 5–6 | Backend, Frontend, SME | L | +| M5 Bewertungs-Engine | Control-Mapping, Reifegrad/Gap, Maßnahmen-Konsolidierung | 7–8 | Backend, SME, Frontend | L | +| M6 Ergebnis/Output | Assessment-Readiness-Auswertung + Export | 9 | Backend, Frontend | M | +| M7 Governance (querlaufend) | Validierungs-Workflow, Aufgaben-Integration, Audit-Trail, Versionierung, Umsetzungshinweise | alle | Backend, Frontend, SME | L | + +**Kürzester Pfad zur Assessment-Readiness:** M1 → M2 → M3 → M4 → M5 → M6. M7 wird parallel eingezogen (Validierung, Aufgaben und Hinweise sollten nicht nachträglich „angeflanscht" werden). Nachweis-Upload ist bewusst spätere Iteration. + +--- + +## 6. Ressourcen-Gesamtübersicht (Rollen im Entwicklungsprojekt) + +| Rolle | Beitrag | Auslastung (grob) | +|---|---|---| +| ISMS/TISAX-SME (Fachredaktion) | Control-Katalog, Templates mit Regeln, Risiko-Katalog, Umsetzungshinweise, Reifegrad-/Bewertungslogik | hoch, durchgehend – der inhaltliche Flaschenhals | +| Backend-Entwicklung | Datenmodell, Regel-/Mapping-Engine, Scoring, Task-Integration, API, Audit-Trail | hoch | +| Frontend-Entwicklung | Wizard-Flow, dynamische Formulare, Editor/Vorschau, Dashboards | hoch | +| Content-/Template-Engineering | Vorlagen mit Platzhaltern und Regel-Tags auszeichnen | mittel, in M3 konzentriert | +| UX/Design | geführter Flow, Statusführung, Hinweis-Panels | mittel | +| QA/Test | Regel-/Scoring-Korrektheit, Dokumentgenerierung, Freigabelogik | mittel–hoch | + +**Wichtig:** Der größte, oft unterschätzte Aufwand liegt nicht in der Software, sondern im **Fachcontent** (Control-Daten, regelfähige Vorlagen, Risiko-Katalog, Umsetzungshinweise). Dieser sollte parallel und früh durch die Beratung erstellt werden, sonst wird er zum kritischen Pfad. + +--- + +## 7. Offene Entscheidungspunkte (vor der technischen Spezifikation zu klären) + +1. **Upload eigener Richtlinien:** nur Control-Zuordnung, oder zusätzlich ein automatischer Abgleich Dokumentinhalt ↔ Anforderungen (Gap-Check)? +2. **Risiko-Bewertungsmethodik:** fest vorgegeben oder mandantenspezifisch konfigurierbar (Skalen, Akzeptanzlinie)? +3. **Versionierung von Katalog/Templates/Risiken:** wie werden laufende Kundeninstanzen bei Updates nachgezogen (automatisch, mit Diff, manuell)? +4. **Validierungsgranularität:** pro Modul, zusätzlich pro Einzelobjekt (einzelne Richtlinie/Risiko/Control)? +5. **Aufgaben-Modul:** existiert bereits mit passender Schnittstelle, oder muss die Task-Erzeugung mitgeplant werden? +6. **Reifegrad-Vorschlag:** rein regelbasiert aus Belegen, oder als Empfehlung mit Pflicht zur Bestätigung durch den Bearbeiter? + +--- + +## 8. Nächster Schritt + +Nach Verifizierung dieses Fahrplans: technische Feinspezifikation je Modul (Datenschemata, Regel-Syntax, API-Verträge, UI-Wireframes, Akzeptanztests) – vorgeschlagene Reihenfolge entlang der Meilensteine M1–M7. diff --git a/docs/wizard-uebergabe/03_Referenz/STAND-dev-branch.HINWEIS.md b/docs/wizard-uebergabe/03_Referenz/STAND-dev-branch.HINWEIS.md new file mode 100644 index 0000000..680ce3f --- /dev/null +++ b/docs/wizard-uebergabe/03_Referenz/STAND-dev-branch.HINWEIS.md @@ -0,0 +1,9 @@ +# Hinweis: STAND-dev-branch.md liegt zentral + +Die im Original-Übergabepaket enthaltene Kopie von `STAND-dev-branch.md` (Stand 2026-07-24) +wurde **bewusst nicht** hier abgelegt, um keinen zweiten, veralteten Stand zu führen. + +**Maßgeblich ist die zentrale Datei im Repo:** [`docs/STAND-dev-branch.md`](../../STAND-dev-branch.md) +(wird nach jeder abgeschlossenen Arbeit gepflegt — Single Source of Truth). + +Weitere Basis-Doku: `docs/HANDOVER-DEV.md`, `docs/HANDOVER-PM.md`, `docs/SPEC.md`. diff --git a/docs/wizard-uebergabe/README.md b/docs/wizard-uebergabe/README.md new file mode 100644 index 0000000..06661fa --- /dev/null +++ b/docs/wizard-uebergabe/README.md @@ -0,0 +1,20 @@ +# Onboarding-Wizard — Übergabepaket (Entwicklung) + +Alles, was die beiden Entwickler und der Berater für die parallele Umsetzung brauchen. + +## Reihenfolge / Einstieg +1. **00_Entwicklerpakete/** — je ein fertiger Umsetzungs-Prompt: + - `Paket-DevA-Wizard-Scoping.md` — Wizard-Shell, Scoping, **AL2/AL3 zentral im Adminportal**. + - `Paket-DevB-Engines-Richtlinien.md` — Aufgaben/Regel-Engine, Fragebogen, **Richtlinien-Import bei Modul-Aktivierung + manueller Upload**. + - Beide enthalten einen **identischen Contracts-Anhang** (Naht) + Datei-Hoheit → konfliktarm parallel. Vorab: 15-Min-Kickoff. +2. **01_Planung/** — Kontext & Gesamtbild: + - `Wizard-Stories.md` (kompletter Story-Backlog F/A/B), `Wizard-Entwickler-Backlog.md` (2-Lane-Plan), + `Onboarding-Wizard-Machbarkeitsanalyse.md` (Ist-Abgleich), `Berater-Anweisung-Fachcontent.md`. +3. **02_Fachcontent_C1-C9/** — Zuarbeit des Fachberaters (ID-konsistent zu `isms-vorlagenpaket-v2`). Start: `C0_README-...`. +4. **03_Referenz/** — Berater-Fahrplan + Dev-Stand `dev`. + +## Wichtig +- Basis-Branch **`dev`**; Feature-Branches `dev/a*-…` bzw. `dev/b*-…`; PR-Ziel `dev`. +- **Definition of Ready** je Story: zugehöriges C-Paket eingespielt, bei Seed-Änderung `python3 seed/isms-vorlagenpaket-v2/_verify.py` → **OK**. +- Kritischer Pfad Fachcontent: C2 → C1/C3 → C5/C6. +- Offene Fachpunkte (C0): neue `FLAG_*` in `variables.schema.json`, P01/D01+VA-20 anlegen, Baseline-`BL-*` normalisieren, ISB-Freigabe. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/messages/de.json b/messages/de.json new file mode 100644 index 0000000..214b9cc --- /dev/null +++ b/messages/de.json @@ -0,0 +1,1136 @@ +{ + "common": { + "appName": "Certvia", + "appTagline": "Informationssicherheit. Endlich einfach.", + "appByline": "Ein Produkt von GEFIM", + "language": "Sprache", + "logout": "Abmelden", + "create": "Anlegen", + "save": "Speichern", + "cancel": "Abbrechen", + "edit": "Bearbeiten", + "delete": "Löschen", + "back": "Zurück", + "close": "Schließen", + "search": "Suchen…", + "actions": "Aktionen", + "add": "Hinzufügen", + "remove": "Entfernen", + "none": "—", + "comingSoon": "Bald verfügbar", + "confirmDelete": "Wirklich löschen?", + "yes": "Ja", + "no": "Nein", + "readOnly": "Nur-Lese-Zugriff." + }, + "nav": { + "dashboard": "Dashboard", + "assetsBia": "Assets & BIA", + "risks": "Risikoanalyse", + "soa": "SoA & Controls", + "measures": "Maßnahmen", + "tasks": "Aufgaben", + "incidents": "Vorfälle", + "policies": "Richtlinien", + "chat": "ISMS-Chat", + "dependencies": "Abhängigkeiten", + "evidence": "Nachweise", + "suppliers": "Lieferanten", + "review": "Management-Review", + "assets": "Asset-Inventar", + "bia": "Business Impact Analyse", + "settings": "Einstellungen", + "admin": "Admin-Konsole", + "onboarding": "Onboarding", + "auditReadiness": "Audit vorbereiten" + }, + "login": { + "title": "Anmelden", + "tagline": "Informationssicherheit. Endlich einfach.", + "subtitle": "Melde dich mit deinem Firmenkonto an.", + "email": "E-Mail-Adresse", + "password": "Passwort", + "mfaOptional": "MFA-Code (falls eingerichtet)", + "submit": "Anmelden", + "forgotPassword": "Passwort vergessen?", + "error": "Anmeldung fehlgeschlagen. Bitte prüfe E-Mail und Passwort." + }, + "dashboard": { + "title": "Dashboard", + "welcome": "Willkommen, {name}", + "tenant": "Mandant", + "roles": "Rollen", + "placeholder": "Die Modul-Dashboards (Risiken, Aufgaben, SoA-Erfüllungsgrad) folgen in den nächsten Iterationen.", + "subtitle": "Willkommen zurück, {name} — Status des ISMS für {tenant}.", + "kpiAssets": "Assets im Inventar", + "kpiProcesses": "Prozesse (BIA)", + "kpiCritical": "Kritische Prozesse", + "kpiCriticalHint": "Kritikalität hoch oder sehr hoch", + "kpiRisks": "Offene Risiken", + "kpiRisksHint": "folgt mit dem Risiko-Modul", + "activity": "Letzte Aktivitäten", + "activitySub": "Audit-Log", + "activityEmpty": "Noch keine Aktivitäten.", + "onboardingTile": "Onboarding-Fortschritt · {percent}%", + "onboardingTileSub": "{done} von {total} Schritten validiert · nächster Schritt: {step}", + "onboardingTileCta": "Zum Wizard →", + "incidentTile": "Vorfälle · Meldefristen", + "incidentTileSub": "{open} offene Meldefrist(en){overdue, plural, =0 {} other {, davon # überfällig}}", + "incidentTileCta": "Zu den Vorfällen →" + }, + "assets": { + "title": "Assets & BIA", + "tabAssets": "Assets", + "tabProcesses": "Prozesse & BIA", + "newAsset": "Neues Asset", + "name": "Name", + "description": "Beschreibung", + "type": "Typ", + "status": "Status", + "owner": "Owner", + "location": "Standort", + "tags": "Tags (kommagetrennt)", + "protection": "Schutzbedarf", + "confidentiality": "Vertraulichkeit", + "integrity": "Integrität", + "availability": "Verfügbarkeit", + "allTypes": "Alle Typen", + "allStatus": "Alle Status", + "empty": "Keine Assets gefunden.", + "detailTitle": "Asset-Details", + "relations": "Abhängigkeiten", + "relationHint": "Dieses Asset hängt ab von:", + "relationReverseHint": "Von diesem Asset hängen ab:", + "addRelation": "Abhängigkeit hinzufügen", + "processes": "Zugeordnete Prozesse", + "linkedRisks": "Zugeordnete Risiken", + "linkedRisksPlaceholder": "Risiken werden mit dem Risiko-Modul (Iteration 3) verknüpft und erscheinen dann hier.", + "editTitle": "Asset bearbeiten", + "createTitle": "Asset anlegen", + "deleted": "Asset gelöscht", + "inheritedNote": "Vererbter Schutzbedarf aus Prozessen (Max-Prinzip) wird bei der BIA berücksichtigt.", + "crumb": "Fachdaten", + "invTitle": "Asset-Inventar", + "invSub": "{count} Werte · Schutzbedarf nach C/I/A · verknüpft mit BIA und Risiko", + "excelImport": "Excel-Import", + "export": "Export", + "kpiTotal": "Assets gesamt", + "kpiTotalTrend": "{count} Typen", + "kpiHigh": "Hoher Schutzbedarf", + "kpiHighTrend": "C/I/A ≥ 3", + "kpiNoOwner": "Ohne Owner", + "kpiNoOwnerTrend": "Zuweisung nötig", + "kpiSuppliers": "Lieferanten", + "kpiSuppliersTrend": "extern", + "all": "Alle", + "filter": "Filtern …", + "noOwner": "kein Owner", + "dependencies": "Abhängigkeiten", + "detailSub": "Stammdaten, Abhängigkeiten & Risiken", + "masterPill": "■ Stammdaten", + "masterNote": "Klassifizierung & Verantwortung", + "depPill": "◆ Abhängigkeiten", + "depNote": "Verknüpfte Assets", + "riskCount": "{count} Risiken", + "criticalTitle": "Kritische IT-Dienste", + "criticalSub": "Automatisch aus Assetinventar und BIA abgeleitet – schreibgeschützt.", + "criticalService": "Kritischer IT-Dienst", + "biaCriticality": "BIA-Kritikalität", + "supportedProcesses": "Gestützte Prozesse", + "criticalEmpty": "Keine kritischen IT-Dienste ermittelt (hohe Verfügbarkeit oder BIA-kritischer Prozess).", + "criticalNote": "Diese Sicht wird laufend aus dem Assetinventar und der Business-Impact-Analyse abgeleitet. RTO/RPO stammen aus den verknüpften Prozessen (strengster Wert). Pflege erfolgt am jeweiligen Asset bzw. Prozess.", + "backToInventory": "Zum Assetinventar" + }, + "assetType": { + "INFORMATION": "Information", + "SYSTEM": "System", + "APPLICATION": "Anwendung", + "LOCATION": "Standort", + "SUPPLIER": "Lieferant", + "PERSON": "Person/Rolle", + "DATA": "Datenkategorie", + "IT_SERVICE": "IT-Service", + "SOFTWARE": "Software", + "PROJECT": "Projekt" + }, + "assetStatus": { + "ACTIVE": "Aktiv", + "PLANNED": "Geplant", + "RETIRED": "Ausgemustert" + }, + "processes": { + "newProcess": "Neuer Prozess", + "name": "Name", + "description": "Beschreibung", + "owner": "Owner", + "criticality": "Kritikalität", + "assets": "Zugeordnete Assets", + "empty": "Keine Prozesse gefunden.", + "detailTitle": "Prozess-Details", + "createTitle": "Prozess anlegen", + "editTitle": "Prozess bearbeiten", + "primaryAssets": "Primäre Assets", + "primaryHint": "Das im Prozess erzeugte/verantwortete Ergebnis-Asset.", + "secondaryAssets": "Sekundäre Assets", + "secondaryHint": "Unterstützende Assets (Systeme, Anwendungen, Personen, Lieferanten).", + "assignAsset": "Asset zuordnen", + "role": "Rolle", + "linkedRisks": "Zugeordnete Risiken", + "linkedRisksPlaceholder": "Risiken werden mit dem Risiko-Modul (Iteration 3) verknüpft und erscheinen dann hier.", + "bia": "Business Impact Analyse", + "rto": "RTO (Stunden)", + "rpo": "RPO (Stunden)", + "mtd": "MTD/MTPD (Stunden)", + "rtoLong": "Recovery Time Objective — max. Zeit bis zur Wiederherstellung", + "rpoLong": "Recovery Point Objective — max. tolerierbarer Datenverlust", + "mtdLong": "Maximum Tolerable Downtime — max. tolerierbarer Ausfall", + "impact": "Schadenshöhe je Schutzziel (1–4)", + "notes": "Anmerkungen / Schadensszenarien", + "biaSaved": "BIA gespeichert", + "noBia": "Noch keine BIA erfasst.", + "biaTitle": "Business Impact Analyse", + "biaSub": "Kritikalität der Geschäftsprozesse · RTO / RPO / MTD", + "biaReport": "BIA-Report (PDF)", + "viewHouse": "Prozesshaus", + "viewTable": "Tabelle", + "kpiTotal": "Prozesse gesamt", + "kpiInScope": "Im Scope", + "kpiBiaDone": "BIA vollständig", + "kpiCritical": "Hohe Kritikalität", + "mainProcs": "{count} Hauptprozesse", + "subProcs": "{count} Teilprozesse", + "subHeading": "Teilprozesse", + "biaOpen": "BIA erfassen", + "biaStatusLegend": "BIA-Status", + "rollupHint": "Werte aus den Teilprozessen zusammengefasst (Kritikalität = Maximum, RTO/RPO/MTD = schärfster Wert).", + "laneEmpty": "Keine Prozesse in dieser Kategorie.", + "depsSection": "Abhängigkeiten", + "depsRequires": "benötigt", + "depsRequiredBy": "wird benötigt von", + "depsAdd": "Abhängigkeit hinzufügen", + "depsSelect": "Prozess wählen …", + "depsNotePlaceholder": "Notiz (optional, z. B. „ERP“)", + "depsNone": "keine", + "depsRequiresHint": "Prozesse, die dieser Prozess benötigt — fällt einer aus, ist dieser Prozess betroffen.", + "depsRequiredByN": "{count} Prozess(e) hängen hiervon ab", + "depsGraphLink": "Abhängigkeits-Graph", + "critTable": "Kritikalität der Prozesse", + "process": "Geschäftsprozess", + "detailHeading": "{name}", + "detailSub": "Zugeordnete Assets nach Rolle", + "critLabel": "Kritikalität: {label}", + "primaryPill": "★ Primäres Asset", + "primaryNote": "Ergebnis, das im Prozess erzeugt wird", + "secondaryPill": "◆ Sekundäre Assets", + "secondaryNote": "Werden zur Bearbeitung benötigt", + "inherits": "vererbt Schutzbedarf an sekundäre Assets", + "showDependencies": "Abhängigkeiten anzeigen →", + "impactShort": "Schadenshöhe (C/I/A)", + "close": "Schließen", + "noAssets": "Noch keine Assets zugeordnet.", + "category": "Prozesskategorie", + "secMaster": "Grunddaten", + "secAssets": "Zugeordnete Assets", + "deleteProcess": "Prozess löschen", + "purpose": "Zweck / Ziel", + "parent": "Hauptprozess", + "noParent": "— kein Hauptprozess (eigenständig)", + "deputyOwner": "Stellvertreter", + "noDeputy": "unbesetzt", + "legalBasis": "Rechtsgrundlage", + "interfaces": "Schnittstellen / Datenflüsse", + "dataProtectionRelevant": "Datenschutzrelevant", + "prototypeRelevant": "Prototypenrelevant", + "catalogCode": "Katalog-Code", + "businessInfo": "Fachliche Informationen" + }, + "processRole": { + "PRIMARY": "Primär", + "SECONDARY": "Sekundär" + }, + "criticality": { + "1": "Niedrig", + "2": "Mittel", + "3": "Hoch", + "4": "Sehr hoch" + }, + "protectionLevel": { + "1": "Normal", + "2": "Erhöht", + "3": "Hoch", + "4": "Sehr hoch" + }, + "processCategory": { + "CORE": "Kernprozess", + "MANAGEMENT": "Managementprozess", + "SUPPORT": "Unterstützender Prozess" + }, + "risks": { + "title": "Risikoanalyse", + "sub": "5×5-Matrix · Eintrittswahrscheinlichkeit × Auswirkung", + "export": "Risikoregister exportieren", + "newRisk": "Risiko", + "heatmap": "Risiko-Heatmap", + "heatmapSub": "Auswirkung (Y) × Eintrittswahrscheinlichkeit (X)", + "register": "Risikoregister", + "registerSub": "Risiken nach Bewertung", + "id": "ID", + "risk": "Risiko", + "rating": "Bewertung", + "treatment": "Behandlung", + "status": "Status", + "owner": "Owner", + "empty": "Noch keine Risiken erfasst.", + "detailHeading": "{ref} · {name}", + "detailSub": "Bewertung, betroffene Assets & Behandlung", + "editTitle": "Risiko bearbeiten", + "createTitle": "Risiko anlegen", + "titleField": "Titel", + "description": "Beschreibung", + "threat": "Bedrohung", + "vulnerability": "Schwachstelle", + "likelihood": "Eintrittswahrscheinlichkeit (1–5)", + "impact": "Auswirkung (1–5)", + "gross": "Brutto-Risiko", + "residual": "Rest-Risiko", + "residualHint": "Nach Umsetzung der Maßnahmen", + "noResidual": "Noch nicht bewertet", + "process": "Geschäftsprozess", + "affectedAssets": "Betroffene Assets", + "affectedNote": "Assets, auf die dieses Risiko wirkt", + "addAsset": "Asset verknüpfen", + "noAssets": "Keine Assets verknüpft.", + "measures": "Notwendige Maßnahmen", + "measuresPlaceholder": "Maßnahmen werden mit dem Maßnahmen-Modul (Iteration 4) verknüpft und erscheinen dann hier.", + "close": "Schließen", + "scoreLabel": "{score} · {level}", + "legendLow": "Gering", + "legendMedium": "Mittel", + "legendElevated": "Erhöht", + "legendHigh": "Hoch", + "legendCritical": "Kritisch", + "axisX": "Eintrittswahrscheinlichkeit →", + "axisY": "Auswirkung ↑", + "likelihoodShort": "Eintrittswahrscheinlichkeit", + "damageShort": "Schaden", + "scoreShort": "Risikowert", + "residualAuto": "Ergibt sich automatisch aus den verknüpften Maßnahmen.", + "noMeasures": "Noch keine Maßnahmen verknüpft — das Rest-Risiko entspricht dem Brutto-Risiko.", + "linkMeasure": "Maßnahme verknüpfen", + "newMeasure": "Neue Maßnahme anlegen & verknüpfen", + "measureTitle": "Titel der Maßnahme", + "reductionL": "Minderung Wahrscheinlichkeit (0,00–4,00)", + "reductionI": "Minderung Schaden (0,00–4,00)", + "reduction": "Minderung", + "createFromAsset": "Risiko erstellen", + "catalogHint": "Aus Katalog wählen oder frei eingeben …", + "addExistingBtn": "Maßnahme hinzufügen", + "createNewBtn": "Neue Maßnahme erstellen", + "measureCol": "Maßnahme", + "statusCol": "Status" + }, + "riskTreatment": { + "AVOID": "Vermeiden", + "MITIGATE": "Vermindern", + "TRANSFER": "Übertragen", + "ACCEPT": "Akzeptieren" + }, + "riskStatus": { + "OPEN": "Offen", + "IN_TREATMENT": "In Behandlung", + "ACCEPTED": "Akzeptiert", + "CLOSED": "Geschlossen" + }, + "riskLevel": { + "low": "Gering", + "medium": "Mittel", + "elevated": "Erhöht", + "high": "Hoch", + "critical": "Kritisch" + }, + "incidents": { + "title": "Vorfälle", + "sub": "Sicherheitsvorfälle erfassen, bewerten, bearbeiten und abschließen", + "crumb": "Betrieb", + "newIncident": "Vorfall melden", + "register": "Vorfallregister", + "registerSub": "Alle Vorfälle des Mandanten (neueste zuerst)", + "empty": "Keine Vorfälle erfasst.", + "id": "Kennung", + "incident": "Vorfall", + "category": "Kategorie", + "severity": "Schweregrad", + "status": "Status", + "owner": "Verantwortlich (Incident-Manager)", + "assignee": "Bearbeiter", + "filter": "Filter", + "filterAll": "Alle", + "createTitle": "Vorfall melden", + "createSub": "Titel, Beschreibung, Kategorie und Betroffenheit erfassen", + "editTitle": "Vorfall bearbeiten", + "detailSub": "Bewertung, Steuerung, Verknüpfungen, Verlauf", + "close": "Schließen", + "titleField": "Titel", + "description": "Beschreibung", + "source": "Kanal / Quelle", + "source_manual": "Intern (manuell)", + "source_email": "E-Mail", + "reporter": "Melder", + "reporterName": "Melder (Name)", + "reporterContact": "Melder (Kontakt)", + "occurredAt": "Eingetreten am", + "detectedAt": "Entdeckt am", + "impactHead": "Auswirkung & Dringlichkeit", + "impactHint": "Schutzziel-Verletzung C/I/A und Dringlichkeit (0–4) — bestimmen den Schweregrad.", + "impactC": "Vertraulichkeit (C)", + "impactI": "Integrität (I)", + "impactA": "Verfügbarkeit (A)", + "impactCia": "Auswirkung C/I/A", + "urgency": "Dringlichkeit", + "priority": "Priorität", + "dataCategories": "Betroffene Datenkategorien", + "dataCategoriesHint": "Kommagetrennt, z. B. Kundendaten, Zugangsdaten", + "personalData": "Personenbezug (→ DSGVO)", + "prototypeData": "Prototyp-/Kundendaten (→ TISAX)", + "nis2Relevant": "NIS2-relevant", + "flags": "Merkmale", + "severityAutoHint": "Der Schweregrad wird automatisch aus Auswirkung × Dringlichkeit abgeleitet (Standard-Matrix) und kann von der Steuerung überschrieben werden.", + "statusChange": "Statuswechsel", + "noTransitions": "Kein weiterer Statuswechsel möglich.", + "applyStatus": "Status setzen", + "steering": "Steuerung", + "restricted": "Vertraulich", + "restrictedToggle": "Vertraulich (nur Verantwortliche + Rollen mit Bearbeiten/Abschließen)", + "rootCause": "Ursache (Root Cause)", + "resolution": "Lösung / Behebung", + "closingNote": "Abschlussnotiz", + "lessonsLearned": "Lessons Learned", + "assets": "Betroffene Assets", + "processes": "Betroffene Prozesse", + "risks": "Verknüpfte Risiken", + "controls": "Betroffene Controls", + "controlsHint": "Welche Controls versagten/betroffen sind (Katalog-Referenz).", + "measures": "Verknüpfte Maßnahmen", + "addAsset": "Asset verknüpfen", + "addProcess": "Prozess verknüpfen", + "addRisk": "Risiko verknüpfen", + "addMeasure": "Maßnahme verknüpfen", + "deleteHint": "Vorfälle werden nicht gelöscht — für die Nachvollziehbarkeit abschließen.", + "comments": "Kommentare", + "noComments": "Noch keine Kommentare.", + "commentPlaceholder": "Kommentar schreiben …", + "addComment": "Kommentieren", + "internal": "Intern", + "timeline": "Verlauf (Audit)", + "noTimeline": "Noch keine Verlaufseinträge.", + "reportingHead": "Meldepflicht & Fristen", + "nis2CategoryLabel": "NIS2-Betroffenheit des Mandanten", + "nis2_keine": "keine", + "nis2_wichtig": "wichtige Einrichtung", + "nis2_wesentlich": "wesentliche Einrichtung", + "reportStatus_none": "keine Meldepflicht", + "reportStatus_pruefung": "Meldepflicht geprüft", + "reportStatus_erstmeldung": "Erstmeldung", + "reportStatus_folgemeldung": "Folgemeldung", + "reportStatus_abschluss": "Abschlussbericht", + "deadlineKind_erstmeldung": "NIS2 Erstmeldung (24 h)", + "deadlineKind_folgemeldung": "NIS2 Folgemeldung (72 h)", + "deadlineKind_abschluss": "NIS2 Abschlussbericht (1 Monat)", + "deadlineKind_dsgvo": "DSGVO-Meldung (Art. 33, 72 h)", + "deadlineKind_reaction": "Interne Reaktionsfrist (SLA)", + "deadlineKind_resolution": "Interne Behebungsfrist (SLA)", + "setReportability": "Meldepflicht setzen/prüfen", + "applyReportability": "Übernehmen", + "reportabilityHint": "Setzt die Meldefristen ab dem Kenntniszeitpunkt. NIS2-Timer nur bei NIS2-Betroffenheit des Mandanten.", + "advanceTo": "Weiter zu:", + "manualSubmitHint": "Die Übermittlung an die Behörde erfolgt manuell (Vorlage/Export). Hier nur Status und Timer.", + "noReportObligation": "Für diesen Vorfall besteht derzeit keine Meldepflicht.", + "dl_meldungHead": "Meldefristen", + "dl_slaHead": "Interne SLA (je Severity)", + "dl_remaining": "noch", + "dl_overdue": "überfällig", + "dl_submitted": "eingereicht", + "dl_none": "Keine Fristen gesetzt.", + "evidence": "Verknüpfte Nachweise", + "reviewHead": "Post-Incident-Review & Wirksamkeit", + "reviewHint": "Kurzbericht speist das Management-Review; die Wirksamkeit der (CAPA-)Maßnahmen dokumentieren (§8).", + "measuresEffectiveness": "Wirksamkeit der Maßnahmen", + "postIncidentReview": "Post-Incident-Review (Kurzbericht)", + "exportHead": "Export & Nachweise", + "exportReport": "Vorfallbericht (Druck/PDF)", + "exportNis2": "NIS2-Meldevorlage", + "exportDsgvo": "DSGVO-Meldevorlage", + "exportHint": "Vorlagen sind vorbefüllt; die Übermittlung an die Behörde erfolgt manuell.", + "exportRegisterCsv": "Register (CSV)", + "exportRegisterXlsx": "Register (XLSX)", + "newRiskFromIncident": "Neues Risiko aus dem Vorfall erzeugen", + "riskTitlePlaceholder": "Risikotitel", + "likelihood": "Eintritt (E)", + "impact": "Auswirkung (S)", + "createRisk": "Risiko anlegen & verknüpfen", + "newMeasureFromIncident": "Maßnahme direkt aus dem Vorfall anlegen", + "measureTitlePlaceholder": "Maßnahmentitel", + "measureOwnerNone": "Verantwortlich (optional)", + "createMeasure": "Maßnahme anlegen & verknüpfen", + "priorityLow": "niedrig", + "priorityMedium": "mittel", + "priorityHigh": "hoch", + "newEvidence": "Nachweis (Referenz/Text) anlegen", + "evidenceTitlePlaceholder": "Titel des Nachweises", + "evidenceRefPlaceholder": "Referenz/Link (optional)", + "createEvidence": "Nachweis anlegen & verknüpfen" + }, + "incidentCategory": { + "malware": "Schadsoftware", + "phishing": "Phishing / Social Engineering", + "unauthorized_access": "Unbefugter Zugriff", + "data_loss": "Datenabfluss / -verlust", + "outage": "Systemausfall / Verfügbarkeit", + "physical": "Physisch (Zutritt / Diebstahl)", + "misconfiguration": "Fehlbedienung / Konfiguration", + "supplier": "Lieferant / Drittpartei", + "prototype_customer_data": "Prototyp / Kundendaten", + "other": "Sonstiges" + }, + "incidentStatus": { + "neu": "Neu", + "triage": "Triage", + "in_bearbeitung": "In Bearbeitung", + "eingedaemmt": "Eingedämmt", + "behoben": "Behoben", + "abgeschlossen": "Abgeschlossen", + "wiedereroeffnet": "Wiedereröffnet" + }, + "incidentSeverity": { + "niedrig": "Niedrig", + "mittel": "Mittel", + "hoch": "Hoch", + "kritisch": "Kritisch" + }, + "measures": { + "title": "Aufgaben & Maßnahmen", + "sub": "Kanban-Board · Maßnahmen aus Risiken, Audits und Vorfällen", + "crumb": "Betrieb", + "newMeasure": "Maßnahme", + "board": "Maßnahmen-Board", + "empty": "Keine Maßnahmen.", + "detailHeading": "{ref} · {name}", + "detailSub": "Status, Verantwortung & verknüpfte Risiken", + "editTitle": "Maßnahme bearbeiten", + "createTitle": "Maßnahme anlegen", + "titleField": "Titel", + "description": "Beschreibung", + "status": "Status", + "priority": "Priorität", + "owner": "Verantwortlich", + "dueDate": "Fällig am", + "linkedRisks": "Verknüpfte Risiken", + "linkedRisksNote": "Diese Maßnahme mindert folgende Risiken", + "noRisks": "Keine Risiken verknüpft.", + "close": "Schließen", + "overdue": "überfällig", + "dragHint": "Karten per Drag-and-Drop zwischen den Spalten verschieben." + }, + "measureStatus": { + "OPEN": "Offen", + "IN_PROGRESS": "In Umsetzung", + "DONE": "Erledigt" + }, + "measurePriority": { + "LOW": "Niedrig", + "MEDIUM": "Mittel", + "HIGH": "Hoch" + }, + "dependencies": { + "title": "Abhängigkeiten & kritische Pfade", + "sub": "Verkettung von Prozessen und Assets · kritische Pfade & Single Points of Failure", + "crumb": "Fachdaten", + "search": "Suchen …", + "criticalToggle": "Kritische Pfade", + "onlyProcesses": "Nur Prozesse", + "fit": "Zentrieren", + "graphView": "Netzwerkgraph", + "analysis": "Analyse", + "spofTitle": "Single Points of Failure", + "spofNone": "Keine SPOF erkannt.", + "spofHint": "{count} kritische Prozesse hängen davon ab", + "critPathTitle": "Kritischster Pfad", + "critPathNone": "Kein kritischer Pfad.", + "critProcesses": "Kritische Prozesse", + "critEdges": "Kritische Kanten", + "legend": "Legende", + "legCritical": "Kritischer Pfad", + "legStandard": "Standard-Abhängigkeit", + "legSpof": "Single Point of Failure", + "legCrit": "Kritisch (K≥3)", + "empty": "Noch keine Prozesse/Assets für einen Graphen vorhanden.", + "openGraph": "Im Abhängigkeitsgraph anzeigen" + }, + "suppliers": { + "title": "Lieferanten & Dienstleister", + "sub": "VDA-ISA 2027 Kap. 6 · NIS2 Lieferkette (Art. 21(2)(d))", + "crumb": "Fachdaten", + "new": "Lieferant", + "newSupplier": "Neuer Lieferant", + "ref": "ID", + "kpiTotal": "Lieferanten", + "kpiNis2": "NIS2-relevant", + "kpiExpiring": "Ablaufend (90 T.)", + "kpiReviews": "Reviews fällig", + "name": "Name", + "sector": "Sektor", + "services": "Leistung / IT-Services", + "criticality": "Kritikalität", + "dataCategories": "Datenkategorien (kommagetrennt)", + "protection": "Schutzbedarf", + "nis2": "NIS2-relevant (Lieferkette)", + "status": "Status", + "contact": "Kontakt", + "nextReview": "Nächstes Review", + "notes": "Anmerkungen", + "empty": "Keine Lieferanten erfasst.", + "detailSub": "Bewertung, Verträge, Nachweise & Verantwortung", + "createTitle": "Lieferant anlegen", + "editTitle": "Lieferant bearbeiten", + "masterPill": "■ Stammdaten", + "catalog": "VDA-ISA 2027 · Kap. 6 Supplier Relationships", + "catalogNote": "Reifegrad je Prüfziel (Ziel 3)", + "target": "Ziel", + "maturity": "Reifegrad", + "references": "Referenzen", + "objective": "Zielbild", + "must": "Muss", + "should": "Soll", + "high": "Hoher Schutzbedarf", + "veryHigh": "Sehr hoher Schutzbedarf", + "sga": "Simplified Group Assessment", + "assessments": "Sicherheitsbewertungen", + "addAssessment": "Bewertung hinzufügen", + "score": "Score", + "result": "Ergebnis", + "type": "Typ", + "date": "Datum", + "contracts": "Verträge", + "addContract": "Vertrag hinzufügen", + "avDpa": "AV/DPA (Art. 28)", + "securityClauses": "Sicherheitsklauseln", + "flowdown": "Flow-down (Subunternehmer)", + "customerTransparency": "Kunden-Transparenz", + "validFrom": "Gültig ab", + "validTo": "Gültig bis", + "reference": "Referenz", + "ndas": "NDA / Geheimhaltung", + "addNda": "NDA hinzufügen", + "parties": "Parteien", + "infoScope": "Informationsart", + "subject": "Gegenstand", + "obligations": "Pflichten", + "extensionStatus": "Verlängerung", + "evidence": "Nachweise & Assurance", + "addEvidence": "Nachweis hinzufügen", + "kind": "Art", + "protectsCia": "Deckt (C/I/A)", + "adequacy": "Angemessenheit geprüft", + "expires": "läuft ab", + "raci": "Verantwortung (Shared Responsibility)", + "addRaci": "Zuordnung hinzufügen", + "itService": "IT-Service", + "requirement": "Anforderung", + "responsible": "Verantwortlich", + "isaApplicability": "ISA-Anwendbarkeit", + "localControls": "Lokale Schutzmaßnahmen", + "subcontractors": "Subunternehmer (4th Party)", + "addSub": "Subunternehmer hinzufügen", + "flowdownObl": "Flow-down-Pflicht", + "decision": "Risikobasierte Managemententscheidung", + "addDecision": "Entscheidung protokollieren", + "reasonNoAudit": "Grund (kein Audit/Label)", + "decisionText": "Entscheidung", + "decidedBy": "Entschieden von", + "recordRef": "Aktenzeichen", + "decisionNeeded": "Kein Third-Party-Audit/TISAX-Label mit geprüfter Angemessenheit vorhanden — eine dokumentierte risikobasierte Managemententscheidung ist erforderlich.", + "assets": "Betroffene Assets", + "close": "Schließen", + "none": "—", + "add": "Hinzufügen", + "risks": "Risiken", + "isbApproval": "ISB-Freigabe Reifegrad", + "isbValue": "ISB-Wert", + "justification": "Begründung (bei Abweichung Pflicht)", + "approve": "Freigeben", + "approvalNote": "Abweichung vom berechneten Wert wird mit Begründung im Audit-Log erfasst.", + "customerReq": "Kundenanforderungen weitergegeben", + "linkedAssets": "Verknüpfte Assets", + "derivedLevel": "Abgeleitete Stufe", + "conformity": "Konformität" + }, + "assessmentType": { + "QUESTIONNAIRE": "Fragebogen", + "SELF_ASSESSMENT": "Self-Assessment", + "AUDIT": "Audit" + }, + "assessmentStatus": { + "SENT": "Versendet", + "RECEIVED": "Eingegangen", + "EVALUATED": "Bewertet", + "OVERDUE": "Überfällig" + }, + "evidenceKind": { + "CERTIFICATE": "Zertifikat", + "TISAX_LABEL": "TISAX-Label", + "ATTESTATION": "Attestierung", + "AUDIT_REPORT": "Auditbericht", + "SELF_ASSESSMENT": "Self-Assessment" + }, + "responsibleParty": { + "CLIENT": "Kunde", + "SUPPLIER": "Lieferant", + "SHARED": "Geteilt" + }, + "supplierStatus": { + "ACTIVE": "Aktiv", + "ONBOARDING": "Onboarding", + "UNDER_REVIEW": "In Prüfung", + "OFFBOARDED": "Beendet" + }, + "services": { + "tabSuppliers": "Lieferanten", + "tabServices": "IT-Services", + "title": "IT-Services", + "newService": "IT-Service", + "ref": "ID", + "name": "Name", + "provider": "Provider (Lieferant)", + "internal": "Intern betrieben", + "criticality": "Kritikalität", + "protection": "Schutzbedarf", + "raciCoverage": "RACI dokumentiert", + "empty": "Keine IT-Services erfasst.", + "createTitle": "IT-Service anlegen", + "editTitle": "IT-Service bearbeiten", + "detailSub": "Asset-artig · Verantwortung (RACI) · Risiken", + "notes": "Anmerkungen", + "linkedAssets": "Verknüpfte Assets", + "linkedProcesses": "Prozesse", + "risks": "Risiken", + "noProvider": "kein Provider", + "raci": "Verantwortungsmatrix (Shared Responsibility)", + "raciNote": "Anwendbarkeit der ISA-Controls je Service — erfüllt 6.1.3", + "addControl": "Control hinzufügen", + "control": "Control", + "controlTitle": "Titel", + "applicable": "Anwendbar", + "responsibility": "Verantwortung", + "evidence": "Nachweis", + "raciEmpty": "Noch keine Controls zugeordnet.", + "close": "Schließen", + "none": "—", + "tabSoftware": "Software" + }, + "raciParty": { + "PROVIDER": "Provider", + "US": "Wir", + "SHARED": "Geteilt" + }, + "policies": { + "crumb": "ISMS-Dokumentation", + "title": "Richtlinien & Verfahren", + "sub": "VDA-ISA 2027 — Leitlinie, Richtlinien, Verfahrensanweisungen und Register", + "library": "Bibliothek", + "coverage": "Coverage-Matrix", + "byDomain": "Nach Fachbereich", + "domainResponsible": "Zuständig", + "domainUnassigned": "Nicht besetzt", + "domainNone": "Ohne Fachbereich", + "domainSet": "Fachbereich zuordnen", + "deriveDomains": "Fachbereiche ableiten", + "deriveDomainsDone": "{n} Fachbereiche aus dem primären Control abgeleitet.", + "deriveDomainsNone": "Alle Dokumente haben bereits einen Fachbereich.", + "actions": "Aktionen", + "submitReview": "Zur Prüfung geben", + "all": "Alle", + "code": "Kürzel", + "docTitle": "Titel", + "type": "Typ", + "version": "Version", + "status": "Status", + "coverageCol": "Abdeckung", + "controlsN": "{n} Controls", + "empty": "Keine Dokumente gefunden.", + "close": "Schließen", + "docInfo": "Dokumenteninformationen", + "operationalizes": "Operationalisiert Richtlinie", + "procedures": "Verfahren", + "control": "ISA-Control", + "policy": "Richtlinie", + "reqIds": "Anforderungs-IDs", + "coverageHint": "{controls} Controls · {reqs} Anforderungen (MUSS/SOLL) über Richtlinien und operationalisierende Verfahren.", + "kpiDocs": "Dokumente", + "kpiDocsTrend": "Leitlinie · Richtlinien · Verfahren · Register", + "kpiControls": "Abgedeckte Controls", + "kpiControlsTrend": "VDA-ISA 2027", + "kpiMust": "MUSS-Anforderungen", + "kpiShould": "SOLL-Anforderungen", + "openFullTable": "Vollständige Tabelle öffnen", + "backToLibrary": "Zurück zur Bibliothek", + "backToDoc": "Zurück zum Dokument", + "editableInline": "direkt in der Ansicht bearbeitbar", + "edit": "Bearbeiten", + "editTitle": "Dokument bearbeiten", + "editHint": "Änderungen werden direkt gespeichert. Der Vier-Augen-Freigabe-Workflow mit Versionierung folgt. Variablenwerte gelten zentral für alle Dokumente.", + "template": "Vorlage (Markdown)", + "docVariables": "Dokument-Variablen", + "docVariablesHint": "Nur die in diesem Dokument vorkommenden Variablen. Änderungen wirken in allen Dokumenten (eine Pflegestelle).", + "flagOn": "aktiv (ja)", + "flagOff": "inaktiv (nein)", + "preview": "Vorschau (Lesemodus)", + "approval": "Freigabe", + "submitForApproval": "Zur Freigabe einreichen", + "submittedBy": "Eingereicht von", + "approve": "Genehmigen (ISB)", + "reject": "Ablehnen", + "rejectReason": "Begründung der Ablehnung", + "fourEyesSelf": "Vier-Augen-Prinzip: Die Freigabe muss durch eine andere Person als den Einreichenden erfolgen.", + "fourEyesNoRight": "Freigabe erfordert die Rolle mit Freigaberecht (z. B. ISB).", + "approvedBy": "Freigegeben von", + "resubmit": "Erneut zur Freigabe einreichen", + "approvalNote": "Vier-Augen: Freigebender ≠ Autor. Versionierung/Diff folgt.", + "saveVariables": "Variablen speichern", + "modeStandard": "Standard (Variablen)", + "modeExpert": "Experten-Modus", + "expertHint": "Voller Vorlagen-Editor: Text, Formatierung, Variablen, Deep-Links & Referenzen. Neue Variablen werden beim Speichern angelegt und sind danach im Standard-Modus pflegbar.", + "byControl": "nach Control", + "byDocument": "nach Dokument", + "assessmentExport": "Assessment-Export", + "requirements": "Anforderung(en)", + "requirement": "Anforderung", + "implementation": "Umsetzung", + "comingSoon": "Bald verfügbar", + "kpiRequirements": "Anforderungen", + "protectionLevel": "Schutzbedarf / TISAX-Level", + "effectiveLevel": "Effektiv", + "globalLevel": "Global", + "levelGlobal": "Global übernehmen", + "levelAl2": "MUSS·SOLL·HOCH", + "levelAl3": "+ SEHR HOCH" + }, + "software": { + "title": "Software-Freigaben", + "tabTitle": "Software", + "newSoftware": "Software erfassen", + "ref": "Kürzel", + "name": "Software", + "provider": "Anbieter/Lieferant", + "noProvider": "kein Anbieter", + "version": "Version/Patch-Stand", + "approvalStatus": "Freigabestatus", + "approvedBy": "Freigeber", + "criticality": "Kritikalität", + "protection": "Schutzbedarf", + "nextReview": "Nächstes Review", + "review": "Review", + "notes": "Notizen", + "createTitle": "Software erfassen", + "editTitle": "Software bearbeiten", + "detailSub": "Freigegebene Software (Whitelist) mit Anbieter und Review", + "masterPill": "Stammdaten", + "linkedRisks": "Zugeordnete Risiken", + "empty": "Noch keine Software erfasst.", + "close": "Schließen", + "none": "—" + }, + "softwareStatus": { + "BEANTRAGT": "Beantragt", + "FREIGEGEBEN": "Freigegeben", + "GESPERRT": "Gesperrt" + }, + "projects": { + "title": "Projekte", + "newProject": "Projekt anlegen", + "ref": "Kürzel", + "name": "Projektname", + "owner": "Projektleitung", + "classification": "IS-Klassifizierung", + "status": "Status", + "isbInvolved": "ISB eingebunden", + "criticality": "Kritikalität", + "protection": "Schutzbedarf", + "notes": "Notizen", + "createTitle": "Projekt anlegen", + "editTitle": "Projekt bearbeiten", + "detailSub": "Informationssicherheit in Projekten (R01 / VA-19)", + "masterPill": "Stammdaten", + "linkedRisks": "Zugeordnete Risiken", + "empty": "Noch keine Projekte erfasst.", + "close": "Schließen", + "none": "—" + }, + "projectStatus": { + "GEPLANT": "Geplant", + "LAUFEND": "Laufend", + "ABGESCHLOSSEN": "Abgeschlossen", + "ABGEBROCHEN": "Abgebrochen" + }, + "onboarding": { + "crumb": "Einrichtung", + "title": "Onboarding-Wizard", + "progress": "{done} von {total} Schritten validiert · {percent}%", + "stepTitle": { + "context": "Kontext & Fakten", + "scope": "Geltungsbereich", + "policy": "Leitlinie & Richtlinien", + "roles": "Team & Rollen", + "criteria": "Kriterien & Skala", + "processes": "Prozesse", + "information": "Information", + "assets": "Assets", + "protection": "Schutzbedarf", + "risks": "Risiken", + "controls": "Controls", + "gap": "GAP-Analyse", + "readiness": "Audit-Readiness" + }, + "status": { + "offen": "Offen", + "in_bearbeitung": "In Bearbeitung", + "zur_validierung": "Zur Validierung", + "validiert": "Validiert", + "zurueckgewiesen": "Zurückgewiesen" + }, + "actions": { + "start": "Bearbeitung starten", + "submit": "Zur Validierung geben", + "validate": "Validieren", + "reset": "Zurücksetzen", + "back": "Zurück", + "next": "Weiter", + "rework": "Nacharbeiten", + "reject": "Zurückweisen" + }, + "placeholderNote": "Dieser Schritt wird in einer folgenden Story mit Inhalt gefüllt. Navigation, Status und Gate sind bereits aktiv.", + "locked": "Gesperrt – vorherige Schritte zuerst validieren.", + "gateHint": "Dieser Schritt ist noch nicht freigegeben — Sie können dennoch fortfahren; die Freigabe kann parallel erfolgen.", + "allDone": "Alle Schritte abgeschlossen", + "rejectCommentPlaceholder": "Begründung der Rückweisung (optional)", + "rejectedTitle": "Zurückgewiesen – bitte nacharbeiten", + "rejectedNoComment": "Keine Begründung hinterlegt.", + "awaitingValidation": "Wartet auf Validierung durch eine berechtigte Rolle." + }, + "auditReadiness": { + "crumb": "Audit vorbereiten", + "title": "Audit-Wizard", + "progress": "{done} von {total} Schritten validiert · {percent}%", + "stepTitle": { + "internal_audit": "Internes Audit", + "audit_gap": "GAP-Konsolidierung", + "audit_evidence": "Nachweis-Check", + "audit_readiness": "Readiness & Management-Review" + }, + "status": { + "offen": "Offen", + "in_bearbeitung": "In Bearbeitung", + "zur_validierung": "Zur Validierung", + "validiert": "Validiert", + "zurueckgewiesen": "Zurückgewiesen" + }, + "actions": { + "start": "Bearbeitung starten", + "submit": "Zur Validierung geben", + "validate": "Validieren", + "reset": "Zurücksetzen", + "back": "Zurück", + "next": "Weiter", + "rework": "Nacharbeiten", + "reject": "Zurückweisen" + }, + "gateHint": "Dieser Schritt ist noch nicht freigegeben — Sie können dennoch fortfahren; die Freigabe kann parallel erfolgen.", + "allDone": "Alle Schritte abgeschlossen", + "rejectCommentPlaceholder": "Begründung der Rückweisung (optional)", + "rejectedTitle": "Zurückgewiesen – bitte nacharbeiten", + "rejectedNoComment": "Keine Begründung hinterlegt.", + "awaitingValidation": "Wartet auf Validierung durch eine berechtigte Rolle." + }, + "processHouse": { + "title": "Prozesshaus", + "intro": "Aktiviere die relevanten Prozesse (Schalter) und arbeite dich je Kachel durch das geführte BIA-Popup. Die Farbe der Kachel zeigt den BIA-Stand.", + "newProcess": "Prozess anlegen", + "toModule": "Zum Prozess-Modul", + "kpiTotal": "Prozesse", + "kpiInScope": "im Scope (aktiv)", + "kpiDone": "BIA komplett", + "legend": "Legende", + "empty": "Noch keine Prozesse. Lege eigene an oder übernimm welche aus dem Standard-Katalog.", + "laneEmpty": "Keine Prozesse in dieser Bahn.", + "unassigned": "unbesetzt", + "deputy": "Stellvertreter", + "openBia": "BIA öffnen", + "details": "Details", + "activate": "Aktivieren", + "deactivate": "Deaktivieren", + "subProcesses": "{count} Teilprozess(e)", + "dotInfo": "Info", + "dotCarrier": "Träger", + "dotCia": "C/I/A", + "dotRisk": "Risiken", + "catalogTitle": "Aus Standard-Katalog übernehmen", + "catalogHint": "Kuratierte Kern-, Management- und Unterstützungsprozesse. „Übernehmen“ legt den Prozess im Register an (Zuordnung über Katalog-Code).", + "adopt": "Übernehmen", + "adopted": "übernommen", + "inclSub": "inkl. {count} Teilprozesse", + "delete": "Löschen", + "deleteConfirm": "Diesen Prozess wirklich entfernen? BIA-Eintrag und Träger-Zuordnungen werden gelöscht, Teilprozesse auf die oberste Ebene gehoben und Risiko-Verknüpfungen gelöst.", + "deleteConfirmBtn": "Endgültig löschen", + "detailSub": "Fachliche Übersicht & BIA (nur Ansicht)", + "children": "Teilprozesse", + "noChildren": "keine", + "status": { + "offen": "offen", + "teilweise": "teilweise", + "komplett": "komplett" + } + }, + "bia": { + "heading": "BIA · {name}", + "stepOf": "Schritt {n} von {total}", + "status": { + "offen": "BIA offen", + "teilweise": "BIA teilweise", + "komplett": "BIA komplett" + }, + "back": "Zurück", + "next": "Weiter", + "open": "offen", + "captured": "erfasst", + "s1Short": "Informationswert", + "s2Short": "Träger", + "s3Short": "Schutzbedarf", + "s4Short": "Risiken", + "s5Short": "Abschluss", + "s1Title": "Informationswert erfassen", + "s1Hint": "Ein Informationswert ist ein primäres Asset (Information/Daten). Katalog-Vorschlag nutzen, per Dedup-Suche erfassen oder mit der vollen Asset-Maske anlegen.", + "catalogLabels": "Katalog-Vorschlag (Klassifizierung)", + "currentPrimaries": "Erfasste Informationswerte", + "noPrimaries": "Noch kein Informationswert erfasst.", + "quickAdd": "Schnell erfassen (mit Dedup + Autovervollständigung)", + "manualToggle": "Manuell mit voller Asset-Inventar-Maske erfassen", + "manualHint": "Legt ein primäres Asset (Typ Information) an und verknüpft es mit diesem Prozess.", + "s2Title": "Sekundäre Assets / Träger", + "s2Hint": "Träger (Systeme, Anwendungen, Standorte, Dienstleister …), auf denen die Informationswerte liegen.", + "suggestedCarriers": "Träger-Vorschläge (Typen)", + "currentCarriers": "Zugeordnete Träger", + "noCarriers": "Noch keine Träger zugeordnet.", + "assignCarrier": "Träger zuordnen", + "noAvailable": "Keine weiteren Assets verfügbar — im Asset-Modul anlegen.", + "newCarrier": "Neues Träger-Asset anlegen", + "newCarrierHint": "Legt ein neues Träger-Asset über die volle Asset-Inventar-Maske an und verknüpft es als Träger (sekundär) mit diesem Prozess.", + "s3Title": "Schutzbedarf C/I/A", + "s3Hint": "Der Schutzbedarf liegt am primären Informationswert. Träger erben per Maximumprinzip.", + "noPrimaryForCia": "Zuerst in Schritt 1 einen Informationswert erfassen.", + "inheritedMax": "Geerbtes Maximum (Träger)", + "inheritedHint": "Träger sollten mindestens dieses Maximum ihrer getragenen primären Werte erfüllen.", + "s4Title": "Risiken je Prozess", + "s4Hint": "Passende Katalog-Risiken übernehmen und im selben Schritt bewerten (Eintritt × Auswirkung = Wert).", + "suggestedRisks": "Empfohlene Risiken (Katalog)", + "adopt": "Übernehmen", + "adopted": "übernommen", + "currentRisks": "Bewertung der Risiken", + "noRisks": "Noch keine Risiken mit diesem Prozess verknüpft.", + "likelihood": "Eintritt (1–5)", + "impact": "Auswirkung (1–5)", + "treatment": "Behandlung", + "statusField": "Status", + "rate": "Bewerten", + "openInRiskModule": "Im Risiko-Modul öffnen", + "linkRisk": "Risiko zuordnen", + "newRisk": "Neues Risiko anlegen", + "riskTitle": "Titel", + "riskDescription": "Beschreibung", + "s5Title": "Abschluss-Übersicht", + "s5Hint": "Kompletter Review aller erfassten Werte. Bei Abschluss wird der BIA-Stand gesetzt (Prozesshaus-Farbe).", + "clInfo": "Informationswert", + "clCarrier": "Träger", + "clCia": "Schutzbedarf", + "clRisk": "Risiken", + "reviewInfo": "Informationswerte & Schutzbedarf", + "reviewCarriers": "Träger", + "reviewRisks": "Risiken", + "finishTitle": "BIA abschließen", + "finishHint": "{done} von {total} Bereichen erfasst.", + "markComplete": "Als komplett markieren", + "markPartial": "Als teilweise markieren", + "criticality": "Kritikalität" + }, + "admin": { + "backToOverview": "Zurück zur Übersicht", + "crumb": "Mandant", + "sub": "Kürzel {slug}{sector} · TISAX {level}", + "statusActive": "Aktiv", + "statusSuspended": "Gesperrt", + "statusArchived": "Archiviert", + "masterDataTitle": "Stammdaten", + "masterDataHint": "Zentrale Quelle der ISMS-Variablen (Mandanten-Einstellungen).", + "orgName": "Unternehmensname", + "orgShort": "Kurzname", + "slug": "Kürzel", + "address": "Adresse", + "sector": "Sektor", + "duns": "D-U-N-S", + "ismsScope": "ISMS-Geltungsbereich", + "tisaxLevel": "TISAX-Level", + "status": "Status", + "notSet": "—", + "mainContactTitle": "Hauptkontakt", + "mainContactHint": "Abgeleitet aus dem/den Mandanten-Administrator(en).", + "mainContactNone": "Kein aktiver Mandanten-Administrator hinterlegt.", + "manageTitle": "Verwaltung", + "manageHint": "Module und Benutzer dieses Mandanten in einem Popup verwalten.", + "manageModules": "Module verwalten", + "manageUsers": "Benutzer verwalten", + "usersCount": "{count} Nutzer", + "modulesTitle": "Module", + "modulesHint": "Deaktivierte Module sind für den Kunden ausgeblendet und serverseitig gesperrt.", + "moduleActive": "Aktiv", + "moduleInactive": "Inaktiv", + "moduleActivate": "Aktivieren", + "moduleDeactivate": "Deaktivieren", + "importTemplates": "Vorlagen importieren", + "importTemplatesTitle": "Vorlagenpaket nicht-destruktiv importieren/aktualisieren", + "modulesModalSub": "Module für {name} aktivieren/deaktivieren", + "usersModalSub": "Benutzer von {name} — anlegen, Rollen, deaktivieren, Passwort zurücksetzen", + "lifecycleTitle": "Lebenszyklus", + "lifecycleActivate": "Aktivieren", + "lifecycleSuspend": "Sperren (Login blockiert)", + "lifecycleArchive": "Archivieren", + "lifecycleNote": "Löschung/Datenexport (DSGVO) und Retention folgen in Phase 2.", + "assessmentTitle": "Assessment-Level (Schutzbedarf)", + "assessmentHint": "Einzige Quelle des Schutzbedarfs — steuert die Schutzbedarf-Flags des Richtlinienmoduls, den Coverage-Filter und den Onboarding-Wizard (dort read-only). Aktuell: {level}.", + "assessmentAl2": "AL2 — MUSS · SOLL · HOCH", + "assessmentAl3": "AL3 — zusätzlich SEHR HOCH", + "mfaTitle": "MFA-Pflicht", + "mfaHint": "Bei Aktivierung müssen alle Nutzer dieses Mandanten beim nächsten Login eine Zwei-Faktor-Authentifizierung einrichten. Aktuell: {state}.", + "mfaStateOn": "aktiv", + "mfaStateOff": "aus", + "mfaActivate": "MFA-Pflicht aktivieren", + "mfaDeactivate": "MFA-Pflicht deaktivieren", + "policyLangTitle": "Sprache der Richtlinien", + "policyLangHint": "Bestimmt, in welcher Sprache das Vorlagenpaket importiert/aktualisiert wird. Wirkt auf künftige Importe; bereits importierte Richtlinien bleiben unverändert, bis der Mandant unter Paket-Updates übernimmt. Aktuell: {lang}.", + "policyLangDe": "Deutsch", + "policyLangEn": "English", + "auditTitle": "Audit-Trail", + "auditHint": "Nachvollziehbare Aktivitäten dieses Mandanten — wer hat wann was geändert.", + "auditView": "Audit-Trail einsehen", + "auditSub": "Aktivitäten von {name} (neueste zuerst, letzte 200)", + "userCreate": "Benutzer anlegen", + "userCreateSub": "Neuer Nutzer für {name}", + "userEdit": "Benutzer bearbeiten — {name}", + "close": "Schließen", + "frameworksTitle": "Normen / Rahmenwerke", + "frameworksHint": "Aktiv: {list}. Steuert Anforderungssicht, SoA und Auswertung. Mindestens eine Norm muss aktiv bleiben.", + "frameworksTisax": "TISAX / VDA ISA", + "frameworksIso": "ISO/IEC 27001", + "frameworksActivate": "Aktivieren", + "frameworksDeactivate": "Deaktivieren", + "frameworksActive": "Aktiv", + "frameworksNote": "Beim Aktivieren wird das Vorlagenpaket der Norm importiert. Beim Deaktivieren bleiben die Bewertungen erhalten und werden nur stillgelegt." + } +} diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..aa5a69d --- /dev/null +++ b/messages/en.json @@ -0,0 +1,1136 @@ +{ + "common": { + "appName": "Certvia", + "appTagline": "Information security. Finally simple.", + "appByline": "A GEFIM product", + "language": "Language", + "logout": "Sign out", + "create": "Create", + "save": "Save", + "cancel": "Cancel", + "edit": "Edit", + "delete": "Delete", + "back": "Back", + "close": "Close", + "search": "Search…", + "actions": "Actions", + "add": "Add", + "remove": "Remove", + "none": "—", + "comingSoon": "Coming soon", + "confirmDelete": "Really delete?", + "yes": "Yes", + "no": "No", + "readOnly": "Read-only access." + }, + "nav": { + "dashboard": "Dashboard", + "assetsBia": "Assets & BIA", + "risks": "Risk analysis", + "soa": "SoA & controls", + "measures": "Measures", + "tasks": "Tasks", + "incidents": "Incidents", + "policies": "Policies", + "chat": "ISMS chat", + "dependencies": "Dependencies", + "evidence": "Evidence", + "suppliers": "Suppliers", + "review": "Management review", + "assets": "Asset inventory", + "bia": "Business impact analysis", + "settings": "Settings", + "admin": "Admin console", + "onboarding": "Onboarding", + "auditReadiness": "Prepare audit" + }, + "login": { + "title": "Sign in", + "tagline": "Information security. Finally simple.", + "subtitle": "Sign in with your company account.", + "email": "E-mail address", + "password": "Password", + "mfaOptional": "MFA code (if enabled)", + "submit": "Sign in", + "forgotPassword": "Forgot password?", + "error": "Sign-in failed. Please check e-mail and password." + }, + "dashboard": { + "title": "Dashboard", + "welcome": "Welcome, {name}", + "tenant": "Tenant", + "roles": "Roles", + "placeholder": "Module dashboards (risks, tasks, SoA coverage) follow in upcoming iterations.", + "subtitle": "Welcome back, {name} — ISMS status for {tenant}.", + "kpiAssets": "Assets in inventory", + "kpiProcesses": "Processes (BIA)", + "kpiCritical": "Critical processes", + "kpiCriticalHint": "criticality high or very high", + "kpiRisks": "Open risks", + "kpiRisksHint": "coming with the risk module", + "activity": "Recent activity", + "activitySub": "Audit log", + "activityEmpty": "No activity yet.", + "onboardingTile": "Onboarding progress · {percent}%", + "onboardingTileSub": "{done} of {total} steps validated · next step: {step}", + "onboardingTileCta": "Open wizard →", + "incidentTile": "Incidents · reporting deadlines", + "incidentTileSub": "{open} open reporting deadline(s){overdue, plural, =0 {} other {, # overdue}}", + "incidentTileCta": "Go to incidents →" + }, + "assets": { + "title": "Assets & BIA", + "tabAssets": "Assets", + "tabProcesses": "Processes & BIA", + "newAsset": "New asset", + "name": "Name", + "description": "Description", + "type": "Type", + "status": "Status", + "owner": "Owner", + "location": "Location", + "tags": "Tags (comma-separated)", + "protection": "Protection needs", + "confidentiality": "Confidentiality", + "integrity": "Integrity", + "availability": "Availability", + "allTypes": "All types", + "allStatus": "All statuses", + "empty": "No assets found.", + "detailTitle": "Asset details", + "relations": "Dependencies", + "relationHint": "This asset depends on:", + "relationReverseHint": "Depending on this asset:", + "addRelation": "Add dependency", + "processes": "Assigned processes", + "linkedRisks": "Assigned risks", + "linkedRisksPlaceholder": "Risks will be linked with the risk module (iteration 3) and appear here.", + "editTitle": "Edit asset", + "createTitle": "Create asset", + "deleted": "Asset deleted", + "inheritedNote": "Inherited protection needs from processes (max principle) are considered in the BIA.", + "crumb": "Core data", + "invTitle": "Asset inventory", + "invSub": "{count} assets · protection needs by C/I/A · linked to BIA and risk", + "excelImport": "Excel import", + "export": "Export", + "kpiTotal": "Total assets", + "kpiTotalTrend": "{count} types", + "kpiHigh": "High protection needs", + "kpiHighTrend": "C/I/A ≥ 3", + "kpiNoOwner": "Without owner", + "kpiNoOwnerTrend": "assignment needed", + "kpiSuppliers": "Suppliers", + "kpiSuppliersTrend": "external", + "all": "All", + "filter": "Filter …", + "noOwner": "no owner", + "dependencies": "Dependencies", + "detailSub": "Master data, dependencies & risks", + "masterPill": "■ Master data", + "masterNote": "Classification & responsibility", + "depPill": "◆ Dependencies", + "depNote": "Linked assets", + "riskCount": "{count} risks", + "criticalTitle": "Critical IT services", + "criticalSub": "Automatically derived from asset inventory and BIA – read-only.", + "criticalService": "Critical IT service", + "biaCriticality": "BIA criticality", + "supportedProcesses": "Supported processes", + "criticalEmpty": "No critical IT services identified (high availability or BIA-critical process).", + "criticalNote": "This view is derived continuously from the asset inventory and the business impact analysis. RTO/RPO come from the linked processes (strictest value). Maintain data on the respective asset or process.", + "backToInventory": "Back to inventory" + }, + "assetType": { + "INFORMATION": "Information", + "SYSTEM": "System", + "APPLICATION": "Application", + "LOCATION": "Location", + "SUPPLIER": "Supplier", + "PERSON": "Person/role", + "DATA": "Data category", + "IT_SERVICE": "IT service", + "SOFTWARE": "Software", + "PROJECT": "Project" + }, + "assetStatus": { + "ACTIVE": "Active", + "PLANNED": "Planned", + "RETIRED": "Retired" + }, + "processes": { + "newProcess": "New process", + "name": "Name", + "description": "Description", + "owner": "Owner", + "criticality": "Criticality", + "assets": "Assigned assets", + "empty": "No processes found.", + "detailTitle": "Process details", + "createTitle": "Create process", + "editTitle": "Edit process", + "primaryAssets": "Primary assets", + "primaryHint": "The result asset produced/owned by this process.", + "secondaryAssets": "Secondary assets", + "secondaryHint": "Supporting assets (systems, applications, people, suppliers).", + "assignAsset": "Assign asset", + "role": "Role", + "linkedRisks": "Assigned risks", + "linkedRisksPlaceholder": "Risks will be linked with the risk module (iteration 3) and appear here.", + "bia": "Business impact analysis", + "rto": "RTO (hours)", + "rpo": "RPO (hours)", + "mtd": "MTD/MTPD (hours)", + "rtoLong": "Recovery Time Objective — max. time to recovery", + "rpoLong": "Recovery Point Objective — max. tolerable data loss", + "mtdLong": "Maximum Tolerable Downtime — max. tolerable outage", + "impact": "Damage level per protection goal (1–4)", + "notes": "Notes / damage scenarios", + "biaSaved": "BIA saved", + "noBia": "No BIA recorded yet.", + "biaTitle": "Business impact analysis", + "biaSub": "Criticality of business processes · RTO / RPO / MTD", + "biaReport": "BIA report (PDF)", + "viewHouse": "Process house", + "viewTable": "Table", + "kpiTotal": "Processes total", + "kpiInScope": "In scope", + "kpiBiaDone": "BIA complete", + "kpiCritical": "High criticality", + "mainProcs": "{count} main processes", + "subProcs": "{count} sub-processes", + "subHeading": "Sub-processes", + "biaOpen": "Record BIA", + "biaStatusLegend": "BIA status", + "rollupHint": "Aggregated from sub-processes (criticality = maximum, RTO/RPO/MTD = tightest value).", + "laneEmpty": "No processes in this category.", + "depsSection": "Dependencies", + "depsRequires": "requires", + "depsRequiredBy": "required by", + "depsAdd": "Add dependency", + "depsSelect": "Choose process …", + "depsNotePlaceholder": "Note (optional, e.g. \"ERP\")", + "depsNone": "none", + "depsRequiresHint": "Processes this one requires — if one fails, this process is affected.", + "depsRequiredByN": "{count} process(es) depend on this", + "depsGraphLink": "Dependency graph", + "critTable": "Process criticality", + "process": "Business process", + "detailHeading": "{name}", + "detailSub": "Assigned assets by role", + "critLabel": "Criticality: {label}", + "primaryPill": "★ Primary asset", + "primaryNote": "Result produced by the process", + "secondaryPill": "◆ Secondary assets", + "secondaryNote": "Required for processing", + "inherits": "inherits protection needs to secondary assets", + "showDependencies": "Show dependencies →", + "impactShort": "Damage level (C/I/A)", + "close": "Close", + "noAssets": "No assets assigned yet.", + "category": "Process category", + "secMaster": "Basic data", + "secAssets": "Assigned assets", + "deleteProcess": "Delete process", + "purpose": "Purpose / objective", + "parent": "Parent process", + "noParent": "— no parent (standalone)", + "deputyOwner": "Deputy", + "noDeputy": "unassigned", + "legalBasis": "Legal basis", + "interfaces": "Interfaces / data flows", + "dataProtectionRelevant": "Data-protection relevant", + "prototypeRelevant": "Prototype relevant", + "catalogCode": "Catalog code", + "businessInfo": "Business information" + }, + "processRole": { + "PRIMARY": "Primary", + "SECONDARY": "Secondary" + }, + "criticality": { + "1": "Low", + "2": "Medium", + "3": "High", + "4": "Very high" + }, + "protectionLevel": { + "1": "Normal", + "2": "Elevated", + "3": "High", + "4": "Very high" + }, + "processCategory": { + "CORE": "Core process", + "MANAGEMENT": "Management process", + "SUPPORT": "Supporting process" + }, + "risks": { + "title": "Risk analysis", + "sub": "5×5 matrix · likelihood × impact", + "export": "Export risk register", + "newRisk": "Risk", + "heatmap": "Risk heatmap", + "heatmapSub": "Impact (Y) × likelihood (X)", + "register": "Risk register", + "registerSub": "Risks by rating", + "id": "ID", + "risk": "Risk", + "rating": "Rating", + "treatment": "Treatment", + "status": "Status", + "owner": "Owner", + "empty": "No risks recorded yet.", + "detailHeading": "{ref} · {name}", + "detailSub": "Rating, affected assets & treatment", + "editTitle": "Edit risk", + "createTitle": "Create risk", + "titleField": "Title", + "description": "Description", + "threat": "Threat", + "vulnerability": "Vulnerability", + "likelihood": "Likelihood (1–5)", + "impact": "Impact (1–5)", + "gross": "Gross risk", + "residual": "Residual risk", + "residualHint": "After implementing measures", + "noResidual": "Not yet rated", + "process": "Business process", + "affectedAssets": "Affected assets", + "affectedNote": "Assets this risk applies to", + "addAsset": "Link asset", + "noAssets": "No assets linked.", + "measures": "Required measures", + "measuresPlaceholder": "Measures will be linked with the measures module (iteration 4) and appear here.", + "close": "Close", + "scoreLabel": "{score} · {level}", + "legendLow": "Low", + "legendMedium": "Medium", + "legendElevated": "Elevated", + "legendHigh": "High", + "legendCritical": "Critical", + "axisX": "Likelihood →", + "axisY": "Impact ↑", + "likelihoodShort": "Likelihood", + "damageShort": "Damage", + "scoreShort": "Risk score", + "residualAuto": "Derived automatically from the linked measures.", + "noMeasures": "No measures linked yet — the residual risk equals the gross risk.", + "linkMeasure": "Link measure", + "newMeasure": "Create & link new measure", + "measureTitle": "Measure title", + "reductionL": "Reduction likelihood (0.00–4.00)", + "reductionI": "Reduction damage (0.00–4.00)", + "reduction": "Reduction", + "createFromAsset": "Create risk", + "catalogHint": "Pick from catalog or type freely …", + "addExistingBtn": "Add measure", + "createNewBtn": "Create new measure", + "measureCol": "Measure", + "statusCol": "Status" + }, + "riskTreatment": { + "AVOID": "Avoid", + "MITIGATE": "Mitigate", + "TRANSFER": "Transfer", + "ACCEPT": "Accept" + }, + "riskStatus": { + "OPEN": "Open", + "IN_TREATMENT": "In treatment", + "ACCEPTED": "Accepted", + "CLOSED": "Closed" + }, + "riskLevel": { + "low": "Low", + "medium": "Medium", + "elevated": "Elevated", + "high": "High", + "critical": "Critical" + }, + "incidents": { + "title": "Incidents", + "sub": "Capture, assess, handle and close security incidents", + "crumb": "Operations", + "newIncident": "Report incident", + "register": "Incident register", + "registerSub": "All incidents of the tenant (newest first)", + "empty": "No incidents recorded.", + "id": "Reference", + "incident": "Incident", + "category": "Category", + "severity": "Severity", + "status": "Status", + "owner": "Owner (incident manager)", + "assignee": "Assignee", + "filter": "Filter", + "filterAll": "All", + "createTitle": "Report incident", + "createSub": "Capture title, description, category and impact", + "editTitle": "Edit incident", + "detailSub": "Assessment, steering, links, history", + "close": "Close", + "titleField": "Title", + "description": "Description", + "source": "Channel / source", + "source_manual": "Internal (manual)", + "source_email": "Email", + "reporter": "Reporter", + "reporterName": "Reporter (name)", + "reporterContact": "Reporter (contact)", + "occurredAt": "Occurred at", + "detectedAt": "Detected at", + "impactHead": "Impact & urgency", + "impactHint": "Protection-goal breach C/I/A and urgency (0–4) — determine the severity.", + "impactC": "Confidentiality (C)", + "impactI": "Integrity (I)", + "impactA": "Availability (A)", + "impactCia": "Impact C/I/A", + "urgency": "Urgency", + "priority": "Priority", + "dataCategories": "Affected data categories", + "dataCategoriesHint": "Comma-separated, e.g. customer data, credentials", + "personalData": "Personal data (→ GDPR)", + "prototypeData": "Prototype/customer data (→ TISAX)", + "nis2Relevant": "NIS2 relevant", + "flags": "Attributes", + "severityAutoHint": "Severity is derived automatically from impact × urgency (default matrix) and can be overridden by steering.", + "statusChange": "Status change", + "noTransitions": "No further status change possible.", + "applyStatus": "Set status", + "steering": "Steering", + "restricted": "Restricted", + "restrictedToggle": "Restricted (owner + roles with manage/close only)", + "rootCause": "Root cause", + "resolution": "Resolution", + "closingNote": "Closing note", + "lessonsLearned": "Lessons learned", + "assets": "Affected assets", + "processes": "Affected processes", + "risks": "Linked risks", + "controls": "Affected controls", + "controlsHint": "Which controls failed/were affected (catalog reference).", + "measures": "Linked measures", + "addAsset": "Link asset", + "addProcess": "Link process", + "addRisk": "Link risk", + "addMeasure": "Link measure", + "deleteHint": "Incidents are not deleted — close them for traceability.", + "comments": "Comments", + "noComments": "No comments yet.", + "commentPlaceholder": "Write a comment …", + "addComment": "Comment", + "internal": "Internal", + "timeline": "History (audit)", + "noTimeline": "No history entries yet.", + "reportingHead": "Reporting obligation & deadlines", + "nis2CategoryLabel": "Tenant NIS2 classification", + "nis2_keine": "none", + "nis2_wichtig": "important entity", + "nis2_wesentlich": "essential entity", + "reportStatus_none": "no reporting obligation", + "reportStatus_pruefung": "obligation reviewed", + "reportStatus_erstmeldung": "initial report", + "reportStatus_folgemeldung": "follow-up report", + "reportStatus_abschluss": "final report", + "deadlineKind_erstmeldung": "NIS2 initial report (24 h)", + "deadlineKind_folgemeldung": "NIS2 follow-up report (72 h)", + "deadlineKind_abschluss": "NIS2 final report (1 month)", + "deadlineKind_dsgvo": "GDPR notification (Art. 33, 72 h)", + "deadlineKind_reaction": "Internal reaction SLA", + "deadlineKind_resolution": "Internal resolution SLA", + "setReportability": "Set/review reporting obligation", + "applyReportability": "Apply", + "reportabilityHint": "Sets the reporting deadlines from the time of knowledge. NIS2 timers only if the tenant is in NIS2 scope.", + "advanceTo": "Advance to:", + "manualSubmitHint": "Submission to the authority is manual (template/export). This only tracks status and timers.", + "noReportObligation": "This incident currently has no reporting obligation.", + "dl_meldungHead": "Reporting deadlines", + "dl_slaHead": "Internal SLA (by severity)", + "dl_remaining": "in", + "dl_overdue": "overdue by", + "dl_submitted": "submitted", + "dl_none": "No deadlines set.", + "evidence": "Linked evidence", + "reviewHead": "Post-incident review & effectiveness", + "reviewHint": "The short report feeds the management review; document the effectiveness of the (CAPA) measures (§8).", + "measuresEffectiveness": "Effectiveness of measures", + "postIncidentReview": "Post-incident review (short report)", + "exportHead": "Export & evidence", + "exportReport": "Incident report (print/PDF)", + "exportNis2": "NIS2 notification template", + "exportDsgvo": "GDPR notification template", + "exportHint": "Templates are pre-filled; submission to the authority is manual.", + "exportRegisterCsv": "Register (CSV)", + "exportRegisterXlsx": "Register (XLSX)", + "newRiskFromIncident": "Create a new risk from the incident", + "riskTitlePlaceholder": "Risk title", + "likelihood": "Likelihood (L)", + "impact": "Impact (I)", + "createRisk": "Create & link risk", + "newMeasureFromIncident": "Create a measure directly from the incident", + "measureTitlePlaceholder": "Measure title", + "measureOwnerNone": "Owner (optional)", + "createMeasure": "Create & link measure", + "priorityLow": "low", + "priorityMedium": "medium", + "priorityHigh": "high", + "newEvidence": "Create evidence (reference/text)", + "evidenceTitlePlaceholder": "Evidence title", + "evidenceRefPlaceholder": "Reference/link (optional)", + "createEvidence": "Create & link evidence" + }, + "incidentCategory": { + "malware": "Malware", + "phishing": "Phishing / social engineering", + "unauthorized_access": "Unauthorized access", + "data_loss": "Data breach / loss", + "outage": "System outage / availability", + "physical": "Physical (access / theft)", + "misconfiguration": "Misoperation / configuration", + "supplier": "Supplier / third party", + "prototype_customer_data": "Prototype / customer data", + "other": "Other" + }, + "incidentStatus": { + "neu": "New", + "triage": "Triage", + "in_bearbeitung": "In progress", + "eingedaemmt": "Contained", + "behoben": "Resolved", + "abgeschlossen": "Closed", + "wiedereroeffnet": "Reopened" + }, + "incidentSeverity": { + "niedrig": "Low", + "mittel": "Medium", + "hoch": "High", + "kritisch": "Critical" + }, + "measures": { + "title": "Tasks & measures", + "sub": "Kanban board · measures from risks, audits and incidents", + "crumb": "Operations", + "newMeasure": "Measure", + "board": "Measures board", + "empty": "No measures.", + "detailHeading": "{ref} · {name}", + "detailSub": "Status, responsibility & linked risks", + "editTitle": "Edit measure", + "createTitle": "Create measure", + "titleField": "Title", + "description": "Description", + "status": "Status", + "priority": "Priority", + "owner": "Responsible", + "dueDate": "Due date", + "linkedRisks": "Linked risks", + "linkedRisksNote": "This measure reduces the following risks", + "noRisks": "No risks linked.", + "close": "Close", + "overdue": "overdue", + "dragHint": "Drag cards between columns to change status." + }, + "measureStatus": { + "OPEN": "Open", + "IN_PROGRESS": "In progress", + "DONE": "Done" + }, + "measurePriority": { + "LOW": "Low", + "MEDIUM": "Medium", + "HIGH": "High" + }, + "dependencies": { + "title": "Dependencies & critical paths", + "sub": "Process/asset chains · critical paths & single points of failure", + "crumb": "Core data", + "search": "Search …", + "criticalToggle": "Critical paths", + "onlyProcesses": "Processes only", + "fit": "Fit view", + "graphView": "Network graph", + "analysis": "Analysis", + "spofTitle": "Single points of failure", + "spofNone": "No SPOF detected.", + "spofHint": "{count} critical processes depend on it", + "critPathTitle": "Most critical path", + "critPathNone": "No critical path.", + "critProcesses": "Critical processes", + "critEdges": "Critical edges", + "legend": "Legend", + "legCritical": "Critical path", + "legStandard": "Standard dependency", + "legSpof": "Single point of failure", + "legCrit": "Critical (K≥3)", + "empty": "No processes/assets available for a graph yet.", + "openGraph": "Show in dependency graph" + }, + "suppliers": { + "title": "Suppliers & service providers", + "sub": "VDA-ISA 2027 ch. 6 · NIS2 supply chain (Art. 21(2)(d))", + "crumb": "Core data", + "new": "Supplier", + "newSupplier": "New supplier", + "ref": "ID", + "kpiTotal": "Suppliers", + "kpiNis2": "NIS2-relevant", + "kpiExpiring": "Expiring (90 d)", + "kpiReviews": "Reviews due", + "name": "Name", + "sector": "Sector", + "services": "Service / IT services", + "criticality": "Criticality", + "dataCategories": "Data categories (comma-separated)", + "protection": "Protection needs", + "nis2": "NIS2-relevant (supply chain)", + "status": "Status", + "contact": "Contact", + "nextReview": "Next review", + "notes": "Notes", + "empty": "No suppliers recorded.", + "detailSub": "Assessment, contracts, evidence & responsibility", + "createTitle": "Create supplier", + "editTitle": "Edit supplier", + "masterPill": "■ Master data", + "catalog": "VDA-ISA 2027 · ch. 6 Supplier Relationships", + "catalogNote": "Maturity per objective (target 3)", + "target": "Target", + "maturity": "Maturity", + "references": "References", + "objective": "Objective", + "must": "Must", + "should": "Should", + "high": "High protection", + "veryHigh": "Very high protection", + "sga": "Simplified Group Assessment", + "assessments": "Security assessments", + "addAssessment": "Add assessment", + "score": "Score", + "result": "Result", + "type": "Type", + "date": "Date", + "contracts": "Contracts", + "addContract": "Add contract", + "avDpa": "DPA (Art. 28)", + "securityClauses": "Security clauses", + "flowdown": "Flow-down (subcontractors)", + "customerTransparency": "Customer transparency", + "validFrom": "Valid from", + "validTo": "Valid to", + "reference": "Reference", + "ndas": "NDA / non-disclosure", + "addNda": "Add NDA", + "parties": "Parties", + "infoScope": "Information type", + "subject": "Subject", + "obligations": "Obligations", + "extensionStatus": "Extension", + "evidence": "Evidence & assurance", + "addEvidence": "Add evidence", + "kind": "Kind", + "protectsCia": "Covers (C/I/A)", + "adequacy": "Adequacy checked", + "expires": "expires", + "raci": "Responsibility (shared responsibility)", + "addRaci": "Add assignment", + "itService": "IT service", + "requirement": "Requirement", + "responsible": "Responsible", + "isaApplicability": "ISA applicability", + "localControls": "Local controls", + "subcontractors": "Subcontractors (4th party)", + "addSub": "Add subcontractor", + "flowdownObl": "Flow-down obligation", + "decision": "Risk-based management decision", + "addDecision": "Record decision", + "reasonNoAudit": "Reason (no audit/label)", + "decisionText": "Decision", + "decidedBy": "Decided by", + "recordRef": "Record ref", + "decisionNeeded": "No third-party audit/TISAX label with checked adequacy present — a documented risk-based management decision is required.", + "assets": "Affected assets", + "close": "Close", + "none": "—", + "add": "Add", + "risks": "Risks", + "isbApproval": "ISB maturity approval", + "isbValue": "ISB value", + "justification": "Justification (required on deviation)", + "approve": "Approve", + "approvalNote": "Deviation from the computed value is recorded with justification in the audit log.", + "customerReq": "Customer requirements passed", + "linkedAssets": "Linked assets", + "derivedLevel": "Derived level", + "conformity": "Conformity" + }, + "assessmentType": { + "QUESTIONNAIRE": "Questionnaire", + "SELF_ASSESSMENT": "Self-assessment", + "AUDIT": "Audit" + }, + "assessmentStatus": { + "SENT": "Sent", + "RECEIVED": "Received", + "EVALUATED": "Evaluated", + "OVERDUE": "Overdue" + }, + "evidenceKind": { + "CERTIFICATE": "Certificate", + "TISAX_LABEL": "TISAX label", + "ATTESTATION": "Attestation", + "AUDIT_REPORT": "Audit report", + "SELF_ASSESSMENT": "Self-assessment" + }, + "responsibleParty": { + "CLIENT": "Client", + "SUPPLIER": "Supplier", + "SHARED": "Shared" + }, + "supplierStatus": { + "ACTIVE": "Active", + "ONBOARDING": "Onboarding", + "UNDER_REVIEW": "Under review", + "OFFBOARDED": "Offboarded" + }, + "services": { + "tabSuppliers": "Suppliers", + "tabServices": "IT services", + "title": "IT services", + "newService": "IT service", + "ref": "ID", + "name": "Name", + "provider": "Provider (supplier)", + "internal": "Operated internally", + "criticality": "Criticality", + "protection": "Protection needs", + "raciCoverage": "RACI documented", + "empty": "No IT services recorded.", + "createTitle": "Create IT service", + "editTitle": "Edit IT service", + "detailSub": "Asset-like · responsibility (RACI) · risks", + "notes": "Notes", + "linkedAssets": "Linked assets", + "linkedProcesses": "Processes", + "risks": "Risks", + "noProvider": "no provider", + "raci": "Responsibility matrix (shared responsibility)", + "raciNote": "Applicability of ISA controls per service — fulfils 6.1.3", + "addControl": "Add control", + "control": "Control", + "controlTitle": "Title", + "applicable": "Applicable", + "responsibility": "Responsibility", + "evidence": "Evidence", + "raciEmpty": "No controls assigned yet.", + "close": "Close", + "none": "—", + "tabSoftware": "Software" + }, + "raciParty": { + "PROVIDER": "Provider", + "US": "Us", + "SHARED": "Shared" + }, + "policies": { + "crumb": "ISMS documentation", + "title": "Policies & Procedures", + "sub": "VDA-ISA 2027 — policy, policies, procedures and registers", + "library": "Library", + "coverage": "Coverage matrix", + "byDomain": "By domain", + "domainResponsible": "Responsible", + "domainUnassigned": "Unassigned", + "domainNone": "No domain", + "domainSet": "Assign domain", + "deriveDomains": "Derive domains", + "deriveDomainsDone": "{n} domains derived from the primary control.", + "deriveDomainsNone": "All documents already have a domain.", + "actions": "Actions", + "submitReview": "Submit for review", + "all": "All", + "code": "Code", + "docTitle": "Title", + "type": "Type", + "version": "Version", + "status": "Status", + "coverageCol": "Coverage", + "controlsN": "{n} controls", + "empty": "No documents found.", + "close": "Close", + "docInfo": "Document information", + "operationalizes": "Operationalizes policy", + "procedures": "Procedures", + "control": "ISA control", + "policy": "Policy", + "reqIds": "Requirement IDs", + "coverageHint": "{controls} controls · {reqs} requirements (MUST/SHOULD) across policies and operationalizing procedures.", + "kpiDocs": "Documents", + "kpiDocsTrend": "Policy · policies · procedures · registers", + "kpiControls": "Covered controls", + "kpiControlsTrend": "VDA-ISA 2027", + "kpiMust": "MUST requirements", + "kpiShould": "SHOULD requirements", + "openFullTable": "Open full table", + "backToLibrary": "Back to library", + "backToDoc": "Back to document", + "editableInline": "editable inline in the view", + "edit": "Edit", + "editTitle": "Edit document", + "editHint": "Changes are saved directly. The four-eyes approval workflow with versioning follows. Variable values apply centrally to all documents.", + "template": "Template (Markdown)", + "docVariables": "Document variables", + "docVariablesHint": "Only the variables used in this document. Changes apply across all documents (single source).", + "flagOn": "active (yes)", + "flagOff": "inactive (no)", + "preview": "Preview (read mode)", + "approval": "Approval", + "submitForApproval": "Submit for approval", + "submittedBy": "Submitted by", + "approve": "Approve (ISO)", + "reject": "Reject", + "rejectReason": "Reason for rejection", + "fourEyesSelf": "Four-eyes principle: approval must be done by someone other than the submitter.", + "fourEyesNoRight": "Approval requires the approver role (e.g. ISO).", + "approvedBy": "Approved by", + "resubmit": "Resubmit for approval", + "approvalNote": "Four-eyes: approver ≠ author. Versioning/diff to follow.", + "saveVariables": "Save variables", + "modeStandard": "Standard (variables)", + "modeExpert": "Expert mode", + "expertHint": "Full template editor: text, formatting, variables, deep links & references. New variables are created on save and can then be maintained in standard mode.", + "byControl": "by control", + "byDocument": "by document", + "assessmentExport": "Assessment export", + "requirements": "Requirement(s)", + "requirement": "Requirement", + "implementation": "Implementation", + "comingSoon": "Coming soon", + "kpiRequirements": "Requirements", + "protectionLevel": "Protection level / TISAX", + "effectiveLevel": "Effective", + "globalLevel": "Global", + "levelGlobal": "Inherit global", + "levelAl2": "MUST·SHOULD·HIGH", + "levelAl3": "+ VERY HIGH" + }, + "software": { + "title": "Software approvals", + "tabTitle": "Software", + "newSoftware": "Add software", + "ref": "Ref", + "name": "Software", + "provider": "Provider/Supplier", + "noProvider": "no provider", + "version": "Version/patch level", + "approvalStatus": "Approval status", + "approvedBy": "Approved by", + "criticality": "Criticality", + "protection": "Protection need", + "nextReview": "Next review", + "review": "Review", + "notes": "Notes", + "createTitle": "Add software", + "editTitle": "Edit software", + "detailSub": "Approved software (whitelist) with provider and review", + "masterPill": "Master data", + "linkedRisks": "Linked risks", + "empty": "No software recorded yet.", + "close": "Close", + "none": "—" + }, + "softwareStatus": { + "BEANTRAGT": "Requested", + "FREIGEGEBEN": "Approved", + "GESPERRT": "Blocked" + }, + "projects": { + "title": "Projects", + "newProject": "Add project", + "ref": "Ref", + "name": "Project name", + "owner": "Project lead", + "classification": "IS classification", + "status": "Status", + "isbInvolved": "ISB involved", + "criticality": "Criticality", + "protection": "Protection need", + "notes": "Notes", + "createTitle": "Add project", + "editTitle": "Edit project", + "detailSub": "Information security in projects (R01 / VA-19)", + "masterPill": "Master data", + "linkedRisks": "Linked risks", + "empty": "No projects recorded yet.", + "close": "Close", + "none": "—" + }, + "projectStatus": { + "GEPLANT": "Planned", + "LAUFEND": "Running", + "ABGESCHLOSSEN": "Completed", + "ABGEBROCHEN": "Cancelled" + }, + "onboarding": { + "crumb": "Setup", + "title": "Onboarding wizard", + "progress": "{done} of {total} steps validated · {percent}%", + "stepTitle": { + "context": "Context & facts", + "scope": "Scope", + "policy": "Policy & guidelines", + "roles": "Team & roles", + "criteria": "Criteria & scale", + "processes": "Processes", + "information": "Information", + "assets": "Assets", + "protection": "Protection needs", + "risks": "Risks", + "controls": "Controls", + "gap": "GAP analysis", + "readiness": "Audit readiness" + }, + "status": { + "offen": "Open", + "in_bearbeitung": "In progress", + "zur_validierung": "For validation", + "validiert": "Validated", + "zurueckgewiesen": "Rejected" + }, + "actions": { + "start": "Start", + "submit": "Submit for validation", + "validate": "Validate", + "reset": "Reset", + "back": "Back", + "next": "Next", + "rework": "Rework", + "reject": "Reject" + }, + "placeholderNote": "This step will be filled with content in a later story. Navigation, status and gating are already active.", + "locked": "Locked – validate previous steps first.", + "gateHint": "This step isn't approved yet — you can still continue; approval can happen in parallel.", + "allDone": "All steps completed", + "rejectCommentPlaceholder": "Reason for rejection (optional)", + "rejectedTitle": "Rejected – please rework", + "rejectedNoComment": "No reason provided.", + "awaitingValidation": "Awaiting validation by an authorized role." + }, + "auditReadiness": { + "crumb": "Prepare audit", + "title": "Audit wizard", + "progress": "{done} of {total} steps validated · {percent}%", + "stepTitle": { + "internal_audit": "Internal audit", + "audit_gap": "GAP consolidation", + "audit_evidence": "Evidence check", + "audit_readiness": "Readiness & management review" + }, + "status": { + "offen": "Open", + "in_bearbeitung": "In progress", + "zur_validierung": "For validation", + "validiert": "Validated", + "zurueckgewiesen": "Rejected" + }, + "actions": { + "start": "Start", + "submit": "Submit for validation", + "validate": "Validate", + "reset": "Reset", + "back": "Back", + "next": "Next", + "rework": "Rework", + "reject": "Reject" + }, + "gateHint": "This step isn't approved yet — you can still continue; approval can happen in parallel.", + "allDone": "All steps completed", + "rejectCommentPlaceholder": "Reason for rejection (optional)", + "rejectedTitle": "Rejected – please rework", + "rejectedNoComment": "No reason provided.", + "awaitingValidation": "Awaiting validation by an authorized role." + }, + "processHouse": { + "title": "Process house", + "intro": "Activate the relevant processes (toggle) and work through the guided BIA popup per tile. The tile colour reflects the BIA status.", + "newProcess": "New process", + "toModule": "To process module", + "kpiTotal": "Processes", + "kpiInScope": "in scope (active)", + "kpiDone": "BIA complete", + "legend": "Legend", + "empty": "No processes yet. Create your own or adopt from the standard catalog.", + "laneEmpty": "No processes in this lane.", + "unassigned": "unassigned", + "deputy": "Deputy", + "openBia": "Open BIA", + "details": "Details", + "activate": "Activate", + "deactivate": "Deactivate", + "subProcesses": "{count} sub-process(es)", + "dotInfo": "Info", + "dotCarrier": "Carrier", + "dotCia": "C/I/A", + "dotRisk": "Risks", + "catalogTitle": "Adopt from standard catalog", + "catalogHint": "Curated core, management and support processes. “Adopt” creates the process in the register (mapped via catalog code).", + "adopt": "Adopt", + "adopted": "adopted", + "inclSub": "incl. {count} sub-processes", + "delete": "Delete", + "deleteConfirm": "Really remove this process? Its BIA entry and asset links are deleted, sub-processes are moved to the top level and risk links are detached.", + "deleteConfirmBtn": "Delete permanently", + "detailSub": "Business overview & BIA (read-only)", + "children": "Sub-processes", + "noChildren": "none", + "status": { + "offen": "open", + "teilweise": "partial", + "komplett": "complete" + } + }, + "bia": { + "heading": "BIA · {name}", + "stepOf": "Step {n} of {total}", + "status": { + "offen": "BIA open", + "teilweise": "BIA partial", + "komplett": "BIA complete" + }, + "back": "Back", + "next": "Next", + "open": "open", + "captured": "captured", + "s1Short": "Information value", + "s2Short": "Carriers", + "s3Short": "Protection", + "s4Short": "Risks", + "s5Short": "Summary", + "s1Title": "Capture the information value", + "s1Hint": "An information value is a primary asset (information/data). Use a catalog suggestion, the dedup search, or the full asset mask.", + "catalogLabels": "Catalog suggestion (classification)", + "currentPrimaries": "Captured information values", + "noPrimaries": "No information value captured yet.", + "quickAdd": "Quick capture (with dedup + autocomplete)", + "manualToggle": "Capture manually with the full asset inventory mask", + "manualHint": "Creates a primary asset (type Information) and links it to this process.", + "s2Title": "Secondary assets / carriers", + "s2Hint": "Carriers (systems, applications, locations, suppliers …) that hold the information values.", + "suggestedCarriers": "Carrier suggestions (types)", + "currentCarriers": "Assigned carriers", + "noCarriers": "No carriers assigned yet.", + "assignCarrier": "Assign carrier", + "noAvailable": "No further assets available — create one in the asset module.", + "newCarrier": "Create new carrier asset", + "newCarrierHint": "Creates a new carrier asset via the full asset inventory mask and links it as a carrier (secondary) to this process.", + "s3Title": "Protection needs C/I/A", + "s3Hint": "Protection needs sit on the primary information value. Carriers inherit by the maximum principle.", + "noPrimaryForCia": "First capture an information value in step 1.", + "inheritedMax": "Inherited maximum (carriers)", + "inheritedHint": "Carriers should meet at least this maximum of the primary values they carry.", + "s4Title": "Risks per process", + "s4Hint": "Adopt matching catalog risks and rate them in the same step (likelihood × impact = score).", + "suggestedRisks": "Recommended risks (catalog)", + "adopt": "Adopt", + "adopted": "adopted", + "currentRisks": "Risk rating", + "noRisks": "No risks linked to this process yet.", + "likelihood": "Likelihood (1–5)", + "impact": "Impact (1–5)", + "treatment": "Treatment", + "statusField": "Status", + "rate": "Rate", + "openInRiskModule": "Open in risk module", + "linkRisk": "Link risk", + "newRisk": "Create new risk", + "riskTitle": "Title", + "riskDescription": "Description", + "s5Title": "Summary", + "s5Hint": "Full review of all captured values. On completion the BIA status is set (process-house colour).", + "clInfo": "Information value", + "clCarrier": "Carriers", + "clCia": "Protection", + "clRisk": "Risks", + "reviewInfo": "Information values & protection", + "reviewCarriers": "Carriers", + "reviewRisks": "Risks", + "finishTitle": "Complete BIA", + "finishHint": "{done} of {total} areas captured.", + "markComplete": "Mark as complete", + "markPartial": "Mark as partial", + "criticality": "Criticality" + }, + "admin": { + "backToOverview": "Back to overview", + "crumb": "Tenant", + "sub": "Slug {slug}{sector} · TISAX {level}", + "statusActive": "Active", + "statusSuspended": "Suspended", + "statusArchived": "Archived", + "masterDataTitle": "Master data", + "masterDataHint": "Single source of the ISMS variables (tenant settings).", + "orgName": "Company name", + "orgShort": "Short name", + "slug": "Slug", + "address": "Address", + "sector": "Sector", + "duns": "D-U-N-S", + "ismsScope": "ISMS scope", + "tisaxLevel": "TISAX level", + "status": "Status", + "notSet": "—", + "mainContactTitle": "Main contact", + "mainContactHint": "Derived from the tenant administrator(s).", + "mainContactNone": "No active tenant administrator on record.", + "manageTitle": "Management", + "manageHint": "Manage this tenant's modules and users in a popup.", + "manageModules": "Manage modules", + "manageUsers": "Manage users", + "usersCount": "{count} users", + "modulesTitle": "Modules", + "modulesHint": "Disabled modules are hidden from the customer and blocked server-side.", + "moduleActive": "Active", + "moduleInactive": "Inactive", + "moduleActivate": "Activate", + "moduleDeactivate": "Deactivate", + "importTemplates": "Import templates", + "importTemplatesTitle": "Import/update the template package non-destructively", + "modulesModalSub": "Enable/disable modules for {name}", + "usersModalSub": "Users of {name} — create, roles, deactivate, reset password", + "lifecycleTitle": "Lifecycle", + "lifecycleActivate": "Activate", + "lifecycleSuspend": "Suspend (login blocked)", + "lifecycleArchive": "Archive", + "lifecycleNote": "Deletion/data export (GDPR) and retention follow in phase 2.", + "assessmentTitle": "Assessment level (protection needs)", + "assessmentHint": "Single source of the protection needs — drives the policy module's protection flags, the coverage filter and the onboarding wizard (read-only there). Currently: {level}.", + "assessmentAl2": "AL2 — MUST · SHOULD · HIGH", + "assessmentAl3": "AL3 — additionally VERY HIGH", + "mfaTitle": "MFA requirement", + "mfaHint": "When enabled, every user of this tenant must set up two-factor authentication at their next login. Currently: {state}.", + "mfaStateOn": "on", + "mfaStateOff": "off", + "mfaActivate": "Enable MFA requirement", + "mfaDeactivate": "Disable MFA requirement", + "policyLangTitle": "Policy language", + "policyLangHint": "Determines the language in which the template package is imported/updated. Applies to future imports; already imported policies stay unchanged until the tenant adopts them under package updates. Currently: {lang}.", + "policyLangDe": "German", + "policyLangEn": "English", + "auditTitle": "Audit trail", + "auditHint": "Traceable activity of this tenant — who changed what and when.", + "auditView": "View audit trail", + "auditSub": "Activity of {name} (newest first, last 200)", + "userCreate": "Create user", + "userCreateSub": "New user for {name}", + "userEdit": "Edit user — {name}", + "close": "Close", + "frameworksTitle": "Standards / frameworks", + "frameworksHint": "Active: {list}. Controls the requirement view, SoA and evaluation. At least one standard must remain active.", + "frameworksTisax": "TISAX / VDA ISA", + "frameworksIso": "ISO/IEC 27001", + "frameworksActivate": "Activate", + "frameworksDeactivate": "Deactivate", + "frameworksActive": "Active", + "frameworksNote": "Activating imports the standard's template package. Deactivating keeps the assessments and only puts them dormant." + } +} diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..4bcc68b --- /dev/null +++ b/next.config.ts @@ -0,0 +1,61 @@ +import type { NextConfig } from "next"; +import createNextIntlPlugin from "next-intl/plugin"; + +// Im Dev-Betrieb braucht Turbopack/HMR 'unsafe-eval' und WebSocket-Verbindungen +// zum Dev-Server. Diese Lockerungen gelten NUR in der Entwicklung, nie im Build. +const isDev = process.env.NODE_ENV !== "production"; + +// Content-Security-Policy (F-07) — zweite Verteidigungslinie hinter dem +// HTML-Sanitizing (F-03). +// +// Hinweis Skripte: 'unsafe-inline' ist ein bewusster Zwischenstand. Next.js +// liefert seinen Hydration-Bootstrap als Inline-Skript aus; eine Nonce-basierte +// CSP (Nonce in proxy.ts erzeugen und an <script>/Next durchreichen) ist ein +// eigenes Folgepaket. Bis dahin bleibt 'unsafe-inline' für Skripte bestehen. +const csp = [ + "default-src 'self'", + // Skripte: 'unsafe-inline' als Zwischenstand (s.o.); 'unsafe-eval' nur im Dev + // (Turbopack/HMR wertet zur Laufzeit aus, im Produktionsbuild nicht nötig). + `script-src 'self' 'unsafe-inline'${isDev ? " 'unsafe-eval'" : ""}`, + // Next.js sowie @xyflow/react und Tailwind v4 setzen Inline-Styles. + "style-src 'self' 'unsafe-inline'", + // data: für den MFA-QR-Code (qrcode → data:-URI); blob: für Graph-Bildexport + // (html-to-image) und ähnliche clientseitig erzeugte Bilder. + "img-src 'self' data: blob:", + "font-src 'self' data:", + // Im Dev zusätzlich der HMR-WebSocket des Dev-Servers. + `connect-src 'self'${isDev ? " ws: wss:" : ""}`, + // html-to-image kann Worker aus Blobs erzeugen. + "worker-src 'self' blob:", + "frame-ancestors 'none'", + "form-action 'self'", + "base-uri 'self'", + "object-src 'none'", +].join("; "); + +const securityHeaders = [ + { key: "Content-Security-Policy", value: csp }, + // HSTS bewusst zusätzlich in der App (neben dem Coolify-/Traefik-Proxy). + { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" }, + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "X-Frame-Options", value: "DENY" }, + { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, + { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(), payment=()" }, +]; + +const nextConfig: NextConfig = { + // Standalone-Output für den Docker-Multi-Stage-Build (siehe Dockerfile) + output: "standalone", + async headers() { + return [ + { + source: "/:path*", + headers: securityHeaders, + }, + ]; + }, +}; + +const withNextIntl = createNextIntlPlugin(); + +export default withNextIntl(nextConfig); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d592db2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,15800 @@ +{ + "name": "isms-tool", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "isms-tool", + "version": "0.1.0", + "dependencies": { + "@anthropic-ai/sdk": "^0.115.0", + "@aws-sdk/client-s3": "^3.1103.0", + "@base-ui/react": "^1.6.0", + "@dagrejs/dagre": "^3.0.0", + "@dnd-kit/core": "^6.3.1", + "@node-rs/argon2": "^2.0.2", + "@prisma/adapter-pg": "^7.8.0", + "@prisma/client": "^7.8.0", + "@simplewebauthn/browser": "^9.0.1", + "@simplewebauthn/server": "^9.0.3", + "@xyflow/react": "^12.11.1", + "bullmq": "^6.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "dotenv": "^17.4.2", + "exceljs": "^4.4.0", + "handlebars": "^4.7.9", + "html-to-image": "^1.11.13", + "imapflow": "^1.7.1", + "ioredis": "^5.11.1", + "lucide-react": "^1.23.0", + "mailparser": "^3.9.15", + "marked": "^18.0.5", + "next": "16.2.12", + "next-auth": "5.0.0-beta.32", + "next-intl": "^4.13.1", + "nodemailer": "^8.0.11", + "otplib": "^13.4.1", + "qrcode": "^1.5.4", + "react": "19.2.4", + "react-dom": "19.2.4", + "sanitize-html": "^2.17.6", + "shadcn": "^4.12.0", + "tailwind-merge": "^3.6.0", + "tw-animate-css": "^1.4.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/nodemailer": "^8.0.1", + "@types/qrcode": "^1.5.6", + "@types/react": "^19", + "@types/react-dom": "^19", + "@types/sanitize-html": "^2.16.1", + "eslint": "^9", + "eslint-config-next": "16.2.12", + "prisma": "7.8.0", + "tailwindcss": "^4", + "tsx": "^4.22.4", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.115.0.tgz", + "integrity": "sha512-BJrFIVyjNuU8lfDyIJTvlRYzgQg+zEl78BxE7fq8esULsGz9IRQvGtW5spq3tydmtjQb/GFdooKGdGsetpx+lQ==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@auth/core": { + "version": "0.41.3", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.3.tgz", + "integrity": "sha512-sJ3JMHHkXMD3aOjopv7mOBTO1Ocw4b0fAEXJBz6k7YHLpYQI6C40jCUPc5fNvUKxXRXNE1/sRISA15UrwWJBTw==", + "license": "ISC", + "dependencies": { + "@panva/hkdf": "^1.2.1", + "jose": "^6.0.6", + "oauth4webapi": "^3.3.0", + "preact": "10.24.3", + "preact-render-to-string": "6.5.11" + }, + "peerDependencies": { + "@simplewebauthn/browser": "^9.0.1", + "@simplewebauthn/server": "^9.0.2", + "nodemailer": "^7.0.7 || ^8.0.5" + }, + "peerDependenciesMeta": { + "@simplewebauthn/browser": { + "optional": true + }, + "@simplewebauthn/server": { + "optional": true + }, + "nodemailer": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/checksums": { + "version": "3.1000.26", + "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.26.tgz", + "integrity": "sha512-CGznePoL+1oWCSzqmkvlYMpWQEZohPR3LntjKXXfVH+oh6Kd8d+yHLkjpiAGwPIHAxFe4OAq3aKfRnv/wqWIyA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.1103.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1103.0.tgz", + "integrity": "sha512-FO7SB2vLhZRN3lBHVhMhRm3YKSHK8e917qjB8LMEEhU69cQ0Ahd/OMyezu+KqNANqEtyxfSnFVvYt81x6ZKGZA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/checksums": "^3.1000.26", + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/credential-provider-node": "^3.972.78", + "@aws-sdk/middleware-sdk-s3": "^3.972.72", + "@aws-sdk/signature-v4-multi-region": "^3.996.43", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.977.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.6.tgz", + "integrity": "sha512-QiaJV4/zDrB4ZY2mfeSXSzSTc36W16sZXcGz+SPFk0CJ26gziO0cS+4LjJUMAbdeeBOvS0k0Aq1cZpfGdUXxSw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.2", + "@aws-sdk/xml-builder": "^3.972.37", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.31.1", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.67", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.67.tgz", + "integrity": "sha512-rcIpk5kxUqDaaNa6Xk23pQ6ViY7jlqzmfFWCahQcBT97ddXaXYYwzCen9Tz1Jvo6aJft6wDl5bN44/Jw5B4oLA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.69", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.69.tgz", + "integrity": "sha512-nggwJtZ4eeNsUw5IeWBMXsi1ryct5idi0K+/SCRF3kybLubOMaNTb3XCihXpWMiVpyzyPeIrl0zTkzhBH9porA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.12.tgz", + "integrity": "sha512-pNEf/OeyN5X3VmLKlgSO6TqaWmW10CvI3TfwL1XhsuhYjSLT2VDaxFnCPHnOeQXSaFisMX4jNhpETriqN8DOmg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/credential-provider-env": "^3.972.67", + "@aws-sdk/credential-provider-http": "^3.972.69", + "@aws-sdk/credential-provider-login": "^3.972.74", + "@aws-sdk/credential-provider-process": "^3.972.67", + "@aws-sdk/credential-provider-sso": "^3.973.11", + "@aws-sdk/credential-provider-web-identity": "^3.972.73", + "@aws-sdk/nested-clients": "^3.997.41", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.74", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.74.tgz", + "integrity": "sha512-0AQfDcf99TNmqVKv0owHrw/TQs6i4ZE5t9qmz6NvO53bE/sA/tpXhXL9AAcEP1qHc6Zzjd1UMb69+/9zdhvY3g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/nested-clients": "^3.997.41", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.78", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.78.tgz", + "integrity": "sha512-OgPAnfvbGAMWac6yvxJ1ihslrvDpPVwR68D2csospdNCCyPvHk9JLzYKwz48SNiS1T2znDwHauywRKRFfpyYng==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.67", + "@aws-sdk/credential-provider-http": "^3.972.69", + "@aws-sdk/credential-provider-ini": "^3.973.12", + "@aws-sdk/credential-provider-process": "^3.972.67", + "@aws-sdk/credential-provider-sso": "^3.973.11", + "@aws-sdk/credential-provider-web-identity": "^3.972.73", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.67", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.67.tgz", + "integrity": "sha512-IlUEejorGTWKb4/Dm7K5Yw4QxUmXLThLhrvBmzVBqZFTbW72cv9LTcITmo1dsnYriALE4h68mOq4LB99x6sQ7Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.11.tgz", + "integrity": "sha512-gAQBkBZxUB84d71+pPcI9L+jh2ujhuAVxc/4FgGiWFDjkPBlMKxzd5XDtkSXTFX8Ro7ansnT88+XadasxMeCRw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/nested-clients": "^3.997.41", + "@aws-sdk/token-providers": "3.1103.0", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.73", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.73.tgz", + "integrity": "sha512-SnlEmQa6SjOgs6iOPLUQl1Eyq4AKiAdPQlkOhFhqNfDtDCwibMGvL6QlkSmf3o6vAUSImzdPCxowT5dfQUZP1A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/nested-clients": "^3.997.41", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.72.tgz", + "integrity": "sha512-lSAoVPvQxX1d8TOM6waKDBQrvvZcm4w6pCldFAsRUffEaXq6lYY0pPyew3KlLu6Xqb74DXI42hGvSsbGBLljlw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/signature-v4-multi-region": "^3.996.43", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.41.tgz", + "integrity": "sha512-RDHqPGQWlF6tatA/Tp3rg6oIwtgN9IVderxE+9av2Y93Dfyu+mO1hZ5Bu2jpfZg2rwdNbsssnwM+sLafIczMlQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/signature-v4-multi-region": "^3.996.43", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.43.tgz", + "integrity": "sha512-lKekx8bLBXSv4O+cslk9Zfnw2XKSkWBs3uWL5QGhH2ZAQfNS7FE0vcSSN2vD/AhxX54ZTywWxR4STThoeOXlBA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.2", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1103.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1103.0.tgz", + "integrity": "sha512-N4wy26MNn31ItGVHYHPrEuCIFY4MBBjC+C5v1lJKqIUSA7OZBdhleCY53zCCrXn27hsk7YNOaTuhQu807S4AfQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.6", + "@aws-sdk/nested-clients": "^3.997.41", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.2.tgz", + "integrity": "sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.37.tgz", + "integrity": "sha512-zKq4HQum8JwDyEuyfuI4bbiAcU0KxP6qy+9PR/IsR92IyE/DaBAikzAS50tjxip4bqIIANpCcG+Yyj6CVhXupg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base-ui/react": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.6.0.tgz", + "integrity": "sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@base-ui/utils": "0.3.1", + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } + } + }, + "node_modules/@base-ui/utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.3.1.tgz", + "integrity": "sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@floating-ui/utils": "^0.2.11", + "reselect": "^5.2.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@dagrejs/dagre": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-3.0.0.tgz", + "integrity": "sha512-ZzhnTy1rfuoew9Ez3EIw4L2znPGnYYhfn8vc9c4oB8iw6QAsszbiU0vRhlxWPFnmmNSFAkrYeF1PhM5m4lAN0Q==", + "license": "MIT", + "dependencies": { + "@dagrejs/graphlib": "4.0.1" + } + }, + "node_modules/@dagrejs/graphlib": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-4.0.1.tgz", + "integrity": "sha512-IvcV6FduIIAmLwnH+yun+QtV36SC7mERqa86aClNqmMN09WhmPPYU8ckHrZBozErf+UvHPWOTJYaGYiIcs0DgA==", + "license": "MIT" + }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dotenvx/dotenvx": { + "version": "1.75.1", + "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz", + "integrity": "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@dotenvx/primitives": "^0.8.0", + "commander": "^11.1.0", + "conf": "^10.2.0", + "dotenv": "^17.2.1", + "enquirer": "^2.4.1", + "env-paths": "^2.2.1", + "execa": "^5.1.1", + "fdir": "^6.2.0", + "ignore": "^5.3.0", + "object-treeify": "1.1.33", + "open": "^8.4.2", + "picomatch": "^4.0.4", + "systeminformation": "^5.22.11", + "undici": "^7.11.0", + "which": "^4.0.0", + "yocto-spinner": "^1.1.0" + }, + "bin": { + "dotenvx": "src/cli/dotenvx.js" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@dotenvx/primitives": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@dotenvx/primitives/-/primitives-0.8.0.tgz", + "integrity": "sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==", + "license": "BSD-3-Clause" + }, + "node_modules/@electric-sql/pglite": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz", + "integrity": "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@electric-sql/pglite-socket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.1.tgz", + "integrity": "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "pglite-server": "dist/scripts/server.js" + }, + "peerDependencies": { + "@electric-sql/pglite": "0.4.1" + } + }, + "node_modules/@electric-sql/pglite-tools": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.1.tgz", + "integrity": "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==", + "devOptional": true, + "license": "Apache-2.0", + "peerDependencies": { + "@electric-sql/pglite": "0.4.1" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "license": "MIT", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "license": "MIT" + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "license": "MIT", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "license": "MIT" + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@formatjs/fast-memoize": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.6.tgz", + "integrity": "sha512-H5aexk1Le7T9TPmscacZ+1pR6CTa2n1wq+HDVGXhH8TzUlQQpeXzZs91dRtmFHrbeNbjPFPfQujUqm7MHgVoXQ==", + "license": "MIT" + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.12.tgz", + "integrity": "sha512-YyzzxVgYJ8DELmmkhn0Yr0rUj0dTJFf9Jp628K3S0ysInBWxLVDOS8i3RP91cCp4DMK4WYb4cVMhWA9i4knSJg==", + "license": "MIT", + "dependencies": { + "@formatjs/icu-skeleton-parser": "2.1.10" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.10.tgz", + "integrity": "sha512-XuSva+8ZGawk8VnD5VD6UeH8KarQ/Z022zgjHDoHmlNiAewstXuuzXc0Hk5pGFSdG+nNw5bfJKXqj1ZXHn9yUA==", + "license": "MIT" + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.10.tgz", + "integrity": "sha512-P/IC3qws3jH+1fEs+o0RIFgXKRaQlFehjS5W0FPAqdo6hgzawLl+eD0q0JjheQ3XtoOe5n8WSYfX06KQZI/QJA==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "3.1.6" + } + }, + "node_modules/@hexagon/base64": { + "version": "1.1.28", + "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz", + "integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==", + "license": "MIT" + }, + "node_modules/@hono/node-server": { + "version": "1.19.17", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.17.tgz", + "integrity": "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", + "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", + "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", + "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", + "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", + "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", + "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", + "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", + "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", + "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", + "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", + "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", + "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", + "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", + "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", + "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", + "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@ioredis/commands": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.10.0.tgz", + "integrity": "sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@levischuck/tiny-cbor": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz", + "integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@next/env": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.12.tgz", + "integrity": "sha512-d0Z5Bc13Fa4nR8pFAKx2jay2yhJM16vlfHbTzYnUQAxlNb6B6lmn4hjt69lYNt4kRtyYP6gEM49lPRHNbIyneg==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.12.tgz", + "integrity": "sha512-uF2z/qAK2q7B5/6CpnFcBRX6jOq5iCO+Uqh1UkJhXljX1JwLarLYhhoJadO6dPb6moTprOKewMXheBcbIoSbug==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.12.tgz", + "integrity": "sha512-0W1R0teHWJrqKX0FH20IzzIWAOuGtBxPGuObrxy1lE8hQvCFj49KE8a3WUg0D7sq6rn6zkM4c7YGUnhudBS6oA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.12.tgz", + "integrity": "sha512-Hy5Ls099+aFUmOLmIgPfLqNi6iCwhL3uQCssz5rWk+5Nkc6TUKCE83DY5BbNylfm3+mfwcSFnLRfrZDJhVxdtw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.12.tgz", + "integrity": "sha512-+YqU2h1cQkHsGfvjAsrSmst8UIFBibBGm5x3Xgel8NLMiDQtNOM4sM2GOEMvG5YiOBNeN/Ykk8cQC2S0Xrqljg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.12.tgz", + "integrity": "sha512-0qjhiYBaKAqF63LA1ZWAAnKTzFUguAaZiRa5etMLGGPj/B6uEVjtIZldIzFEp3wHlB0koK6aTzqPtSdplTCjoA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.12.tgz", + "integrity": "sha512-7A3q26W+h7gnA15uqBToNuDqBEFZZcqh0mW2mn4AJh/G5pdg2RVE3n4slzLEliASZFG3NmsbEzng/x2Sh09mBg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.12.tgz", + "integrity": "sha512-qSjL/uppm+cbh21s72Ss8gkiOhQ4dExWHNGOWy6eZV7STj5WsKehgxT61beSsOj+YYQuTplL376lOCdMQU5T8w==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.12.tgz", + "integrity": "sha512-X6hzsOUJac/e7AWSbn9gQ9nzHld1xWP5iyjHpYWvud8pufB679O1xg4JDyKr8Xd69Jvd+kM2Der6uftiZCmjYA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.12.tgz", + "integrity": "sha512-F6fakeHuFTLOPt0bslQJdf+xtT+WIP9DVn/m4y1w1mRnVPyh3D/cNvzlRkxM444xfm+IvvYNSOrKiA2CDJ0Uxw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@node-rs/argon2": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-2.0.2.tgz", + "integrity": "sha512-t64wIsPEtNd4aUPuTAyeL2ubxATCBGmeluaKXEMAFk/8w6AJIVVkeLKMBpgLW6LU2t5cQxT+env/c6jxbtTQBg==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@node-rs/argon2-android-arm-eabi": "2.0.2", + "@node-rs/argon2-android-arm64": "2.0.2", + "@node-rs/argon2-darwin-arm64": "2.0.2", + "@node-rs/argon2-darwin-x64": "2.0.2", + "@node-rs/argon2-freebsd-x64": "2.0.2", + "@node-rs/argon2-linux-arm-gnueabihf": "2.0.2", + "@node-rs/argon2-linux-arm64-gnu": "2.0.2", + "@node-rs/argon2-linux-arm64-musl": "2.0.2", + "@node-rs/argon2-linux-x64-gnu": "2.0.2", + "@node-rs/argon2-linux-x64-musl": "2.0.2", + "@node-rs/argon2-wasm32-wasi": "2.0.2", + "@node-rs/argon2-win32-arm64-msvc": "2.0.2", + "@node-rs/argon2-win32-ia32-msvc": "2.0.2", + "@node-rs/argon2-win32-x64-msvc": "2.0.2" + } + }, + "node_modules/@node-rs/argon2-android-arm-eabi": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-2.0.2.tgz", + "integrity": "sha512-DV/H8p/jt40lrao5z5g6nM9dPNPGEHL+aK6Iy/og+dbL503Uj0AHLqj1Hk9aVUSCNnsDdUEKp4TVMi0YakDYKw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-android-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-2.0.2.tgz", + "integrity": "sha512-1LKwskau+8O1ktKx7TbK7jx1oMOMt4YEXZOdSNIar1TQKxm6isZ0cRXgHLibPHEcNHgYRsJWDE9zvDGBB17QDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-darwin-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-2.0.2.tgz", + "integrity": "sha512-3TTNL/7wbcpNju5YcqUrCgXnXUSbD7ogeAKatzBVHsbpjZQbNb1NDxDjqqrWoTt6XL3z9mJUMGwbAk7zQltHtA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-darwin-x64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-2.0.2.tgz", + "integrity": "sha512-vNPfkLj5Ij5111UTiYuwgxMqE7DRbOS2y58O2DIySzSHbcnu+nipmRKg+P0doRq6eKIJStyBK8dQi5Ic8pFyDw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-freebsd-x64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-2.0.2.tgz", + "integrity": "sha512-M8vQZk01qojQfCqQU0/O1j1a4zPPrz93zc9fSINY7Q/6RhQRBCYwDw7ltDCZXg5JRGlSaeS8cUXWyhPGar3cGg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-linux-arm-gnueabihf": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-2.0.2.tgz", + "integrity": "sha512-7EmmEPHLzcu0G2GDh30L6G48CH38roFC2dqlQJmtRCxs6no3tTE/pvgBGatTp/o2n2oyOJcfmgndVFcUpwMnww==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-linux-arm64-gnu": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-2.0.2.tgz", + "integrity": "sha512-6lsYh3Ftbk+HAIZ7wNuRF4SZDtxtFTfK+HYFAQQyW7Ig3LHqasqwfUKRXVSV5tJ+xTnxjqgKzvZSUJCAyIfHew==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-linux-arm64-musl": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-2.0.2.tgz", + "integrity": "sha512-p3YqVMNT/4DNR67tIHTYGbedYmXxW9QlFmF39SkXyEbGQwpgSf6pH457/fyXBIYznTU/smnG9EH+C1uzT5j4hA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-linux-x64-gnu": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-2.0.2.tgz", + "integrity": "sha512-ZM3jrHuJ0dKOhvA80gKJqBpBRmTJTFSo2+xVZR+phQcbAKRlDMSZMFDiKbSTnctkfwNFtjgDdh5g1vaEV04AvA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-linux-x64-musl": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-2.0.2.tgz", + "integrity": "sha512-of5uPqk7oCRF/44a89YlWTEfjsftPywyTULwuFDKyD8QtVZoonrJR6ZWvfFE/6jBT68S0okAkAzzMEdBVWdxWw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-wasm32-wasi": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-2.0.2.tgz", + "integrity": "sha512-U3PzLYKSQYzTERstgtHLd4ZTkOF9co57zTXT77r0cVUsleGZOrd6ut7rHzeWwoJSiHOVxxa0OhG1JVQeB7lLoQ==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@node-rs/argon2-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@node-rs/argon2-win32-arm64-msvc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-2.0.2.tgz", + "integrity": "sha512-Eisd7/NM0m23ijrGr6xI2iMocdOuyl6gO27gfMfya4C5BODbUSP7ljKJ7LrA0teqZMdYHesRDzx36Js++/vhiQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-win32-ia32-msvc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-2.0.2.tgz", + "integrity": "sha512-GsE2ezwAYwh72f9gIjbGTZOf4HxEksb5M2eCaj+Y5rGYVwAdt7C12Q2e9H5LRYxWcFvLH4m4jiSZpQQ4upnPAQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-win32-x64-msvc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-2.0.2.tgz", + "integrity": "sha512-cJxWXanH4Ew9CfuZ4IAEiafpOBCe97bzoKowHCGk5lG/7kR4WF/eknnBlHW9m8q7t10mKq75kruPLtbSDqgRTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@otplib/core": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@otplib/core/-/core-13.4.1.tgz", + "integrity": "sha512-KIXgK1hNtWJEBMTastbe1bpmuais+3f+ATeO8TkMs2rNkfGO1FbQy8+/UWVEu3TR/iTJerU0idkPudaPmLP2BA==", + "license": "MIT" + }, + "node_modules/@otplib/hotp": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@otplib/hotp/-/hotp-13.4.1.tgz", + "integrity": "sha512-g9q04SwpG5ZtMnVkUcgcoAlwCH4YLROZN1qhyBwgkBzqYYVSYhpP6gSGaxGHwePLt1c+e6NqDlgIZN+e1/XPuA==", + "license": "MIT", + "dependencies": { + "@otplib/core": "13.4.1", + "@otplib/uri": "13.4.1" + } + }, + "node_modules/@otplib/plugin-base32-scure": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@otplib/plugin-base32-scure/-/plugin-base32-scure-13.4.1.tgz", + "integrity": "sha512-Fs/r5qisC05SRhT6xWXaypB6PVC0vgWf6zztmi0J5RnQ09OJiPDWCJFH6cDm6ANsrdvB9di7X+Jb7L13BoEbUA==", + "license": "MIT", + "dependencies": { + "@otplib/core": "13.4.1", + "@scure/base": "^2.2.0" + } + }, + "node_modules/@otplib/plugin-crypto-noble": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto-noble/-/plugin-crypto-noble-13.4.1.tgz", + "integrity": "sha512-PJfVW8/1hdS6CfxLheKPZSLTwDq4TijZbN4yRjxlv0ODdzmxpM+wGwWr1JXMdy0xJPxLziydQD5gdVqrR4/gAg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@otplib/core": "13.4.1" + } + }, + "node_modules/@otplib/totp": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@otplib/totp/-/totp-13.4.1.tgz", + "integrity": "sha512-QOkBVPrf6AM4qZaReZPSk9/I8ATVdZpIISJz115MqeVtcrbcr5llPZ0J7804tpnjnp1vCRkI5Qjd47HhgVteBQ==", + "license": "MIT", + "dependencies": { + "@otplib/core": "13.4.1", + "@otplib/hotp": "13.4.1", + "@otplib/uri": "13.4.1" + } + }, + "node_modules/@otplib/uri": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@otplib/uri/-/uri-13.4.1.tgz", + "integrity": "sha512-xaIm7bvICMhoB2rZIR5luiaMdssWR5nY5nXnR1fdezUgZuEO58D6zrGzLp7pQuBmlpmL0HagnscDQFoskp9yiA==", + "license": "MIT", + "dependencies": { + "@otplib/core": "13.4.1" + } + }, + "node_modules/@panva/hkdf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", + "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@peculiar/asn1-android": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.8.0.tgz", + "integrity": "sha512-skLbS+IOGv1lUgDqtChr8xvtvEr3HMse/JGBaL2r1J1o/n7a8wqOrovMtlRq/UXLhxvmLaONP67hwtshgzwfzA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.8.0", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.8.0.tgz", + "integrity": "sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.8.0", + "@peculiar/asn1-x509": "^2.8.0", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.8.0.tgz", + "integrity": "sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.8.0", + "@peculiar/asn1-x509": "^2.8.0", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.8.0.tgz", + "integrity": "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==", + "license": "MIT", + "dependencies": { + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.8.0.tgz", + "integrity": "sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.8.0", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@prisma/adapter-pg": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.8.0.tgz", + "integrity": "sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/driver-adapter-utils": "7.8.0", + "@types/pg": "^8.16.0", + "pg": "^8.16.3", + "postgres-array": "3.0.4" + } + }, + "node_modules/@prisma/client": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.8.0.tgz", + "integrity": "sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/client-runtime-utils": "7.8.0" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/client-runtime-utils": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.8.0.tgz", + "integrity": "sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/config": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.8.0.tgz", + "integrity": "sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.3.4", + "deepmerge-ts": "7.1.5", + "effect": "3.20.0", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.8.0.tgz", + "integrity": "sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/dev": { + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.3.tgz", + "integrity": "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "@electric-sql/pglite": "0.4.1", + "@electric-sql/pglite-socket": "0.1.1", + "@electric-sql/pglite-tools": "0.3.1", + "@hono/node-server": "1.19.11", + "@prisma/get-platform": "7.2.0", + "@prisma/query-plan-executor": "7.2.0", + "@prisma/streams-local": "0.1.2", + "foreground-child": "3.3.1", + "get-port-please": "3.2.0", + "hono": "^4.12.8", + "http-status-codes": "2.3.0", + "pathe": "2.0.3", + "proper-lockfile": "4.1.2", + "remeda": "2.33.4", + "std-env": "3.10.0", + "valibot": "1.2.0", + "zeptomatch": "2.1.0" + } + }, + "node_modules/@prisma/dev/node_modules/@hono/node-server": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@prisma/driver-adapter-utils": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.8.0.tgz", + "integrity": "sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.8.0" + } + }, + "node_modules/@prisma/engines": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.8.0.tgz", + "integrity": "sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.8.0", + "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", + "@prisma/fetch-engine": "7.8.0", + "@prisma/get-platform": "7.8.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a.tgz", + "integrity": "sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz", + "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.8.0" + } + }, + "node_modules/@prisma/fetch-engine": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.8.0.tgz", + "integrity": "sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.8.0", + "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", + "@prisma/get-platform": "7.8.0" + } + }, + "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz", + "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.8.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", + "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0" + } + }, + "node_modules/@prisma/get-platform/node_modules/@prisma/debug": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz", + "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/query-plan-executor": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-7.2.0.tgz", + "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/streams-local": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.2.tgz", + "integrity": "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.12.0", + "better-result": "^2.7.0", + "env-paths": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "engines": { + "bun": ">=1.3.6", + "node": ">=22.0.0" + } + }, + "node_modules/@prisma/streams-local/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@prisma/streams-local/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@prisma/studio-core": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.27.3.tgz", + "integrity": "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@radix-ui/react-toggle": "1.1.10", + "chart.js": "4.5.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0", + "pnpm": "8" + }, + "peerDependencies": { + "@types/react": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@schummar/icu-type-parser": { + "version": "1.21.5", + "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz", + "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", + "license": "MIT" + }, + "node_modules/@scure/base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz", + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.12.0.tgz", + "integrity": "sha512-oELmoyA6ML9jDRMV3kgcMQFKxUfBU0yFVn6yTctVaLT5ygXnxH52I3TZEgV9EhXJC68/uFvE5Daj1/25c0Xa/A==", + "license": "MIT", + "dependencies": { + "domelementtype": "~2.3.0", + "domhandler": "~5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + }, + "peerDependencies": { + "selderee": "~0.12.0" + } + }, + "node_modules/@selderee/plugin-htmlparser2/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/@selderee/plugin-htmlparser2/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/@simplewebauthn/browser": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-9.0.1.tgz", + "integrity": "sha512-wD2WpbkaEP4170s13/HUxPcAV5y4ZXaKo1TfNklS5zDefPinIgXOpgz1kpEvobAsaLPa2KeH7AKKX/od1mrBJw==", + "license": "MIT", + "dependencies": { + "@simplewebauthn/types": "^9.0.1" + } + }, + "node_modules/@simplewebauthn/server": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-9.0.3.tgz", + "integrity": "sha512-FMZieoBosrVLFxCnxPFD9Enhd1U7D8nidVDT4MsHc6l4fdVcjoeHjDueeXCloO1k5O/fZg1fsSXXPKbY2XTzDA==", + "license": "MIT", + "dependencies": { + "@hexagon/base64": "^1.1.27", + "@levischuck/tiny-cbor": "^0.2.2", + "@peculiar/asn1-android": "^2.3.10", + "@peculiar/asn1-ecc": "^2.3.8", + "@peculiar/asn1-rsa": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "@simplewebauthn/types": "^9.0.1", + "cross-fetch": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@simplewebauthn/types": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@simplewebauthn/types/-/types-9.0.1.tgz", + "integrity": "sha512-tGSRP1QvsAvsJmnOlRQyw/mvK9gnPtjEc5fg2+m8n+QUa+D7rvrKkOYyfpy42GTs90X3RDOnqJgfHt+qO67/+w==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@smithy/core": { + "version": "3.31.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.31.1.tgz", + "integrity": "sha512-CyogUINxvi7C7LDsh8Syo6hVJOT9ckz4rG8dRZfTJ8r91HkMY59PnNooaj7WcHyxEkxPfBAmbgztZU+xTo76lg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.4.16", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.16.tgz", + "integrity": "sha512-QfuLWAkLzptffFW980AFeHZFdqds2B64rpEd3uJ6lgs3xVn9QegGMUgUcj+4d7dRrAsya3r58ZKpku97WcFb4w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.6.13", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.13.tgz", + "integrity": "sha512-4fW86pEUOMbrD5nkbyl/tTvPHHWJFbuB2odl6ps9lWfHoXf9HWh3Q/Smh59qH1g7+c/BSZghX6bbUk4gsiMs8A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.9.13", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.13.tgz", + "integrity": "sha512-Nmd/Nl35zfYrd+a6OO2cDJb3GPh9bgTjIUhcM+JFfjpp8/osCgboDV5nCT1I01Pv6R13eSKDKLSoVa5ZB6Zsfw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.6.12", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.12.tgz", + "integrity": "sha512-I6KLtq3H0qqSuV9vLglfi8puHqzygzWHOnI4z/Rdoo+q50vvo18vBRdPAvvEtcaKROz7Zn6qnPa14kRfPH6PcQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz", + "integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", + "integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", + "integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", + "integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", + "integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", + "integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", + "integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", + "integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", + "integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", + "integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", + "integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", + "integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", + "integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.27.tgz", + "integrity": "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz", + "integrity": "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.2.tgz", + "integrity": "sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-x64": "4.3.2", + "@tailwindcss/oxide-freebsd-x64": "4.3.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-x64-musl": "4.3.2", + "@tailwindcss/oxide-wasm32-wasi": "4.3.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz", + "integrity": "sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz", + "integrity": "sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz", + "integrity": "sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz", + "integrity": "sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz", + "integrity": "sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz", + "integrity": "sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz", + "integrity": "sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz", + "integrity": "sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz", + "integrity": "sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz", + "integrity": "sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz", + "integrity": "sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz", + "integrity": "sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.2.tgz", + "integrity": "sha512-rjVWYCa7Ngbi5AarT6k8TkxUG3Wl1QKzHdIZVsjZSzf36Jmo2IKZt/NHRAwly8oDkbBOH0YTu+CHuf9jPxMc+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.2", + "@tailwindcss/oxide": "4.3.2", + "postcss": "^8.5.15", + "tailwindcss": "4.3.2" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", + "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.3", + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@ts-morph/common/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/nodemailer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.1.tgz", + "integrity": "sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/qrcode": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz", + "integrity": "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/sanitize-html": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.1.tgz", + "integrity": "sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "htmlparser2": "^10.1" + } + }, + "node_modules/@types/sanitize-html/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/@types/sanitize-html/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/@types/validate-npm-package-name": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", + "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz", + "integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/type-utils": "8.62.1", + "@typescript-eslint/utils": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.62.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz", + "integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz", + "integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.62.1", + "@typescript-eslint/types": "^8.62.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz", + "integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz", + "integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz", + "integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/utils": "8.62.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz", + "integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz", + "integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.62.1", + "@typescript-eslint/tsconfig-utils": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz", + "integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz", + "integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@xyflow/react": { + "version": "12.11.1", + "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.11.1.tgz", + "integrity": "sha512-L+zBoLGSXham0MnlY8QqjfR7/C5JNw0zxkaey5aZ5XmCgJBAdH4+WRIu8CR40d3l/BdU635V6YbhBK1jMo8/6Q==", + "license": "MIT", + "dependencies": { + "@xyflow/system": "0.0.78", + "classcat": "^5.0.3", + "zustand": "^4.4.0" + }, + "peerDependencies": { + "@types/react": ">=17", + "@types/react-dom": ">=17", + "react": ">=17", + "react-dom": ">=17" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@xyflow/system": { + "version": "0.0.78", + "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.78.tgz", + "integrity": "sha512-lY0z2qP33fUhTva9Vaxrk0lqZta2pkbxB1trHAx1omnJqRtPvDlAQYV2r5fhS6AdpkulYmbNW0svy+A4/t4B/g==", + "license": "MIT", + "dependencies": { + "@types/d3-drag": "^3.0.7", + "@types/d3-interpolate": "^3.0.4", + "@types/d3-selection": "^3.0.10", + "@types/d3-transition": "^3.0.8", + "@types/d3-zoom": "^3.0.8", + "d3-drag": "^3.0.0", + "d3-interpolate": "^3.0.1", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + } + }, + "node_modules/@zone-eu/mailsplit": { + "version": "5.4.15", + "resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.15.tgz", + "integrity": "sha512-c7ZpxauvF4AEkDJlKDYO7iMUtMuqJMBnDWNff1cyx+d7zaBVR3iFEmXhNHOVoMmVyVF3pTZLsLIJsEFKDldOAA==", + "license": "(MIT OR EUPL-1.1+)", + "dependencies": { + "libbase64": "1.3.0", + "libmime": "5.4.2", + "libqp": "2.1.1" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1js": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "license": "MIT", + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axe-core": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", + "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/better-result": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.10.0.tgz", + "integrity": "sha512-oQhh0y1qo2/ZKdAAEvHZAqKKiHOFU5k/bW96fE2ScgQOVkJRiHwB+nOS1SgFsYqRlxMDWvefXi9Q3px7QvgNDw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "license": "MIT", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.17.tgz", + "integrity": "sha512-w+aeW/mkgM4PyRMOJCgi3fOrTm5Q8QY1OSfn2TO2iuDj3ezIHqejmuxbjfPrqUkgqRew1iqkyAn0tr0ZwHD9+w==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/bullmq": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-6.0.0.tgz", + "integrity": "sha512-cWmhfdLYPCPy2Otp1VDSM4ugIHCApahDsCK1qN/eNu/fN47tnaldMSkHvb5MEE69rt8M3e7EucgSTRFMg8Hxgw==", + "license": "MIT", + "dependencies": { + "cron-parser": "5.6.1", + "msgpackr": "2.0.5", + "node-abort-controller": "3.1.1", + "semver": "7.8.5", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=14.17.0" + }, + "peerDependencies": { + "bullmq-otel": ">=2.0.0", + "ioredis": ">=5.0.0", + "pg": ">=8.0.0", + "redis": ">=5.0.0" + }, + "peerDependenciesMeta": { + "bullmq-otel": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "pg": { + "optional": true + }, + "redis": { + "optional": true + } + } + }, + "node_modules/bullmq/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz", + "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "confbox": "^0.2.4", + "defu": "^6.1.6", + "dotenv": "^17.3.1", + "exsolve": "^1.0.8", + "giget": "^3.2.0", + "jiti": "^2.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.0", + "rc9": "^3.0.1" + }, + "peerDependencies": { + "magicast": "*" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001800", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", + "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "license": "MIT/X11", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==", + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/conf": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", + "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==", + "license": "MIT", + "dependencies": { + "ajv": "^8.6.3", + "ajv-formats": "^2.1.1", + "atomically": "^1.7.0", + "debounce-fn": "^4.0.0", + "dot-prop": "^6.0.1", + "env-paths": "^2.2.1", + "json-schema-typed": "^7.0.3", + "onetime": "^5.1.2", + "pkg-up": "^3.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conf/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/conf/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/conf/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/conf/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/conf/node_modules/json-schema-typed": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", + "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==", + "license": "BSD-2-Clause" + }, + "node_modules/conf/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cron-parser": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-5.6.1.tgz", + "integrity": "sha512-QBm4o1PwZiuY7KFbVvW7FLC8bozy7YWzv+Fz6KRS7sQghzcbDZCGxr/Bc5b6TQreAoSwuWVP491dIcK0THCX6A==", + "license": "MIT", + "dependencies": { + "luxon": "^3.7.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT" + }, + "node_modules/debounce-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", + "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-serializer": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz", + "integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==", + "license": "MIT", + "dependencies": { + "domelementtype": "^3.0.0", + "domhandler": "^6.0.0", + "entities": "^8.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz", + "integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/domhandler": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz", + "integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^3.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz", + "integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^3.0.0", + "domelementtype": "^3.0.0", + "domhandler": "^6.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz", + "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.384", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.384.tgz", + "integrity": "sha512-g6KAKY1vkYsADvSPWvdJsuYT0ixdcu6lUtD9P/wJKGBEDlZVXh2AX42j1mPqqaQPDluWjara9ziQ7xqAeXCt5A==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding-japanese": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz", + "integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==", + "license": "MIT", + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.3.tgz", + "integrity": "sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.12.tgz", + "integrity": "sha512-iaaf4vvKo5h2LBdGt0JuRv7t0Ysqr9FMCiFxbptDg8LqOE//mIKR80DdpOnSVM7qjLH3jT8P0aFiwXxBEGZRXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "16.2.12", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.13.0.tgz", + "integrity": "sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/exceljs": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", + "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", + "license": "MIT", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/exsolve": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", + "integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "license": "MIT", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuzzysort": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", + "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "license": "MIT" + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", + "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-port-please": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", + "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/giget/-/giget-3.3.1.tgz", + "integrity": "sha512-r+mvuDjrjMpsdw46Kmeydb8bdHm7wOKw8wNBtTndkjbPjgAp5oUJUxRE76wZFknxIPokfWvep2qSXK37aXE6zg==", + "devOptional": true, + "license": "MIT", + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/grammex": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.13.tgz", + "integrity": "sha512-LnPnhOBLEJEVKS8WFDVaA397L9Kq55Q9oSITJiVLHVdhAclfUkWzQv74KhvZHKL2Q09Pb1XdsrOsZ4LfTFFTEg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/graphmatch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz", + "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hono": { + "version": "4.12.27", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz", + "integrity": "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-to-image": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", + "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", + "license": "MIT" + }, + "node_modules/html-to-text": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-10.0.0.tgz", + "integrity": "sha512-2OH59Gtprdczel+7Rxgpz9hGVJREaf8Lt1H4kZwWHpEn70VQKRuMNGsb2eDbwaTzrYzb0hheiOG1P7Dim0B4dQ==", + "license": "MIT", + "dependencies": { + "@selderee/plugin-htmlparser2": "~0.12.0", + "deepmerge-ts": "^7.1.5", + "dom-serializer": "^2.0.0", + "htmlparser2": "^10.1.0", + "selderee": "~0.12.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + } + }, + "node_modules/html-to-text/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/html-to-text/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/html-to-text/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/html-to-text/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/html-to-text/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/html-to-text/node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/html-to-text/node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/htmlparser2": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-12.0.0.tgz", + "integrity": "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^3.0.0", + "domhandler": "^6.0.0", + "domutils": "^4.0.2", + "entities": "^8.0.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/icu-minify": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.13.1.tgz", + "integrity": "sha512-nFYW2im0WJ3RUVZwabd71J8QTZRtkK1xxZBY7klg7a6KS/os17LZSj9q1VhbRSnk3S8Mv2I7F1izr/aEJ6cUsw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/icu-messageformat-parser": "^3.4.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imapflow": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/imapflow/-/imapflow-1.7.1.tgz", + "integrity": "sha512-etpyRH7wOPQGawjl/5ChgaaX5NRK2fxJAi9EFFNwv0N3FXsvjsL3Qu5dJ4i/myH61Cq2RSTb6vI5T9rXDbXD+g==", + "license": "MIT", + "dependencies": { + "@zone-eu/mailsplit": "5.4.15", + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.3", + "libbase64": "1.3.0", + "libmime": "5.4.2", + "libqp": "2.1.1", + "pino": "10.3.1", + "socks": "2.8.9" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/intl-messageformat": { + "version": "11.2.9", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.9.tgz", + "integrity": "sha512-cGzymZerpDhVXRKjKLgXKda9gI29TU2o88L7gwNMHp3WZVxA/0c5tX52udXbW9JklDApolvMXZG6Dhhdz5eirA==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/fast-memoize": "3.1.6", + "@formatjs/icu-messageformat-parser": "3.5.12" + } + }, + "node_modules/ioredis": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.11.1.tgz", + "integrity": "sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "1.10.0", + "cluster-key-slot": "1.1.1", + "debug": "4.4.3", + "denque": "2.1.0", + "redis-errors": "1.2.0", + "redis-parser": "3.0.0", + "standard-as-callback": "2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", + "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/launder/-/launder-1.7.1.tgz", + "integrity": "sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==", + "license": "MIT", + "dependencies": { + "dayjs": "^1.11.7" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/leac": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.7.0.tgz", + "integrity": "sha512-qMrZeyEekgdRQ9o6a4NAB2EQZrv827GJdn1vnapwSJ90hWRB4TzUSunvacPkxQ2TnNqHNI1/zSt0hlo0crG8Jw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libbase64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "license": "MIT" + }, + "node_modules/libmime": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.4.2.tgz", + "integrity": "sha512-+IQnCOdPiufGBkOii+Ze8F7iniyBzOwvWDbn1DyExBpc9pT2B3IEMQi7GUc/PpqhNUh/sr1SG9UXDITQoR0VIA==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.3", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/libqp": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz", + "integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==", + "license": "MIT" + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "license": "ISC" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "license": "MIT" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "license": "MIT" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lru.min": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", + "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", + "devOptional": true, + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/lucide-react": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.23.0.tgz", + "integrity": "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mailparser": { + "version": "3.9.15", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.15.tgz", + "integrity": "sha512-/5hgybKDMKFS05jAh8OPeEE7N53lj8nF6ywlo89VPjF2TtwqIQbjaxumQWnJIkmaagnJ6u1eansMOViHFxIXwQ==", + "license": "MIT", + "dependencies": { + "@zone-eu/mailsplit": "5.4.15", + "encoding-japanese": "2.2.0", + "he": "1.2.0", + "html-to-text": "10.0.0", + "iconv-lite": "0.7.3", + "libmime": "5.4.2", + "linkify-it": "5.0.2", + "nodemailer": "9.0.5", + "punycode.js": "2.3.1", + "tlds": "1.261.0" + } + }, + "node_modules/mailparser/node_modules/nodemailer": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.5.tgz", + "integrity": "sha512-wvjiKvjczmsN7U/8006JOdXubgBk2XFAbioDMbT+sM7cPs0QrhJTa6KBRX7P5REGGkDcLUz/EarWidb8G8C1jQ==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/marked": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.5.tgz", + "integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-2.0.5.tgz", + "integrity": "sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.4" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" + } + }, + "node_modules/mysql2": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", + "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.0", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "lru.min": "^1.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/next": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.12.tgz", + "integrity": "sha512-iD59eYQWmbFcEbX7v/acG5DRym9iw1DdaPoD0WTA920naWsE25wShzJW4+UvAs8MK9EC2kBfIH6vtto1H1PHGw==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.12", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.12", + "@next/swc-darwin-x64": "16.2.12", + "@next/swc-linux-arm64-gnu": "16.2.12", + "@next/swc-linux-arm64-musl": "16.2.12", + "@next/swc-linux-x64-gnu": "16.2.12", + "@next/swc-linux-x64-musl": "16.2.12", + "@next/swc-win32-arm64-msvc": "16.2.12", + "@next/swc-win32-x64-msvc": "16.2.12", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-auth": { + "version": "5.0.0-beta.32", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.32.tgz", + "integrity": "sha512-CGlChIEWZ6LltNVxrE5yiySMID+Idpmry47JYA5lLwgD8Sx02a8M65VL0TWVz9nbnOioS/tCW/rP/0+mE7Qp4Q==", + "license": "ISC", + "dependencies": { + "@auth/core": "0.41.3" + }, + "peerDependencies": { + "@simplewebauthn/browser": "^9.0.1", + "@simplewebauthn/server": "^9.0.2", + "next": "^14.0.0-0 || ^15.0.0 || ^16.0.0", + "nodemailer": "^7.0.7 || ^8.0.5", + "react": "^18.2.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@simplewebauthn/browser": { + "optional": true + }, + "@simplewebauthn/server": { + "optional": true + }, + "nodemailer": { + "optional": true + } + } + }, + "node_modules/next-intl": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.13.1.tgz", + "integrity": "sha512-aS8KTA+nNhSNJJBlIhxgvU135WzoObwzFwav4wTDti/Gmhxqe0fs/Q343igo8Z7HGqPB/xgmoagwySZAlHmIfA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "^0.8.1", + "@parcel/watcher": "^2.4.1", + "@swc/core": "^1.15.2", + "icu-minify": "^4.13.1", + "negotiator": "^1.0.0", + "next-intl-swc-plugin-extractor": "^4.13.1", + "po-parser": "^2.1.1", + "use-intl": "^4.13.1" + }, + "peerDependencies": { + "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/next-intl-swc-plugin-extractor": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.13.1.tgz", + "integrity": "sha512-RhlH2DR1ViEXzcX7G3tDXAvzNrBL2Ph54Hq/q/9oP9eXQV/okh3UQpA/lx2k9U5Ck83CZOSgH0eFTNi5U+zyXw==", + "license": "MIT" + }, + "node_modules/next-intl/node_modules/@swc/core": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz", + "integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.27" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.43", + "@swc/core-darwin-x64": "1.15.43", + "@swc/core-linux-arm-gnueabihf": "1.15.43", + "@swc/core-linux-arm64-gnu": "1.15.43", + "@swc/core-linux-arm64-musl": "1.15.43", + "@swc/core-linux-ppc64-gnu": "1.15.43", + "@swc/core-linux-s390x-gnu": "1.15.43", + "@swc/core-linux-x64-gnu": "1.15.43", + "@swc/core-linux-x64-musl": "1.15.43", + "@swc/core-win32-arm64-msvc": "1.15.43", + "@swc/core-win32-ia32-msvc": "1.15.43", + "@swc/core-win32-x64-msvc": "1.15.43" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/node-exports-info": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", + "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nodemailer": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.11.tgz", + "integrity": "sha512-nrO/pDAUKl+wXX+lx16tDLbnm0fW6sK/x8mgohaCpg+CdCEl482bD4tCuAZk2DyliruiNTIZxRCoWkDqJEnAiA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oauth4webapi": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", + "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/otplib": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/otplib/-/otplib-13.4.1.tgz", + "integrity": "sha512-o5CxfDw6bh7hoDv0NUUIcc0RqzJ9ipfUrzeKheKJ+vs4rXZnDlA9n4a/7R1cDjpmLjKLix4BgNVRmoDkm5rLSQ==", + "license": "MIT", + "dependencies": { + "@otplib/core": "13.4.1", + "@otplib/hotp": "13.4.1", + "@otplib/plugin-base32-scure": "13.4.1", + "@otplib/plugin-crypto-noble": "13.4.1", + "@otplib/totp": "13.4.1", + "@otplib/uri": "13.4.1" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", + "license": "MIT" + }, + "node_modules/parseley": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.13.1.tgz", + "integrity": "sha512-uNBJZzmb60l6p6VWLTmevizNAGnE0xoSf1n0B4q3ntegDNzcS68NRCcBDZTcyXHxt2XhBChsCuqj4M+nChvE/A==", + "license": "MIT", + "dependencies": { + "leac": "^0.7.0", + "peberminta": "^0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/peberminta": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.10.0.tgz", + "integrity": "sha512-80B2AsU+I4Qdb0ZAPSfe9UwvGzwkM37IKIFEvdS3D/3Ndgv2bsuJ0bfG1+iEYO+l7Gfd4EUJmuRyq7efLgRMzQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + } + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz", + "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.14.0", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.15.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz", + "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz", + "integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz", + "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz", + "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/po-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz", + "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==", + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", + "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", + "devOptional": true, + "license": "Unlicense", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, + "node_modules/postgres-array": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", + "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/preact": { + "version": "10.24.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", + "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/preact-render-to-string": { + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", + "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", + "license": "MIT", + "peerDependencies": { + "preact": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prisma": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.8.0.tgz", + "integrity": "sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "7.8.0", + "@prisma/dev": "0.24.3", + "@prisma/engines": "7.8.0", + "@prisma/studio-core": "0.27.3", + "mysql2": "3.15.3", + "postgres": "3.4.7" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0" + }, + "peerDependencies": { + "better-sqlite3": ">=9.0.0", + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.1.0.tgz", + "integrity": "sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", + "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/rc9": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz", + "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.6", + "destr": "^2.0.5" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/recast": { + "version": "0.23.12", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.12.tgz", + "integrity": "sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/remeda": { + "version": "2.33.4", + "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", + "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/remeda" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/reselect": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sanitize-html": { + "version": "2.17.6", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.6.tgz", + "integrity": "sha512-M4bo9tfv1yfhQZZKkc6dL07ALrGJtfvNOuhX3hU9AVPR/uPQ+nKOJBqTYc7LfMQblTW04mtSWDJWEyLvygJsLA==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^12.0.0", + "is-plain-object": "^5.0.0", + "launder": "^1.7.1", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/selderee": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.12.0.tgz", + "integrity": "sha512-b1YMh3+DHZp59DLna3qVwQ5iOla/nrI6mLBNW02XxU77M3046Df6VLkoaJyFz20VsGIG5kkp+FK0kg4K4HnUFw==", + "license": "MIT", + "dependencies": { + "parseley": "~0.13.1" + }, + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==", + "devOptional": true + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shadcn": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.12.0.tgz", + "integrity": "sha512-o781ieQziCnXH2FKsEqxp1fnbHdbgAPO9inTSPeZ59hQfsZXuMGp3ul8oFSV5KQS4nbUK9b+DrDE6C7OvfKKQQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/plugin-transform-typescript": "^7.28.0", + "@babel/preset-typescript": "^7.27.1", + "@dotenvx/dotenvx": "^1.48.4", + "@modelcontextprotocol/sdk": "^1.26.0", + "@types/validate-npm-package-name": "^4.0.2", + "browserslist": "^4.26.2", + "commander": "^14.0.0", + "cosmiconfig": "^9.0.0", + "dedent": "^1.6.0", + "deepmerge": "^4.3.1", + "diff": "^8.0.2", + "execa": "^9.6.0", + "fast-glob": "^3.3.3", + "fs-extra": "^11.3.1", + "fuzzysort": "^3.1.0", + "kleur": "^4.1.5", + "open": "^11.0.0", + "ora": "^8.2.0", + "postcss": "^8.5.6", + "postcss-selector-parser": "^7.1.0", + "prompts": "^2.4.2", + "recast": "^0.23.11", + "stringify-object": "^5.0.0", + "tailwind-merge": "^3.0.1", + "ts-morph": "^26.0.0", + "tsconfig-paths": "^4.2.0", + "undici": "^7.27.2", + "validate-npm-package-name": "^7.0.1", + "zod": "^3.24.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "shadcn": "dist/index.js" + }, + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/shadcn/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/shadcn/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/shadcn/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/shadcn/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/sharp": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", + "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.3", + "@img/sharp-darwin-x64": "0.35.3", + "@img/sharp-freebsd-wasm32": "0.35.3", + "@img/sharp-libvips-darwin-arm64": "1.3.2", + "@img/sharp-libvips-darwin-x64": "1.3.2", + "@img/sharp-libvips-linux-arm": "1.3.2", + "@img/sharp-libvips-linux-arm64": "1.3.2", + "@img/sharp-libvips-linux-ppc64": "1.3.2", + "@img/sharp-libvips-linux-riscv64": "1.3.2", + "@img/sharp-libvips-linux-s390x": "1.3.2", + "@img/sharp-libvips-linux-x64": "1.3.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", + "@img/sharp-libvips-linuxmusl-x64": "1.3.2", + "@img/sharp-linux-arm": "0.35.3", + "@img/sharp-linux-arm64": "0.35.3", + "@img/sharp-linux-ppc64": "0.35.3", + "@img/sharp-linux-riscv64": "0.35.3", + "@img/sharp-linux-s390x": "0.35.3", + "@img/sharp-linux-x64": "0.35.3", + "@img/sharp-linuxmusl-arm64": "0.35.3", + "@img/sharp-linuxmusl-x64": "0.35.3", + "@img/sharp-webcontainers-wasm32": "0.35.3", + "@img/sharp-win32-arm64": "0.35.3", + "@img/sharp-win32-ia32": "0.35.3", + "@img/sharp-win32-x64": "0.35.3" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", + "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-keys": "^1.0.0", + "is-obj": "^3.0.0", + "is-regexp": "^3.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/stringify-object?sponsor=1" + } + }, + "node_modules/stringify-object/node_modules/is-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", + "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/systeminformation": { + "version": "5.31.11", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.11.tgz", + "integrity": "sha512-I6O7iaUj23AXRgCPDDnvi3xHvdOLp4+1YMbF+X194lJwY1NeWojgHJPhslVKcmTtrLTguRk3QJK+xEdTiI3P0w==", + "license": "MIT", + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", + "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/thread-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz", + "integrity": "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==", + "license": "MIT", + "dependencies": { + "real-require": "^1.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/thread-stream/node_modules/real-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-1.0.0.tgz", + "integrity": "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tlds": { + "version": "1.261.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", + "license": "MIT", + "bin": { + "tlds": "bin.js" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "license": "MIT/X11", + "engines": { + "node": "*" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-morph": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", + "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.27.0", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz", + "integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.62.1", + "@typescript-eslint/parser": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/utils": "8.62.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "license": "MIT", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-intl": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.13.1.tgz", + "integrity": "sha512-UU5C3zAC7yVg3m7rq5C8VF5J5jhAfvS19Wi9bPNCB9xB7jQYBsUcrqfdxs4Mxl9XR3x6BDB5K++iAw7/rcm3gg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "^3.1.0", + "@schummar/icu-type-parser": "1.21.5", + "icu-minify": "^4.13.1", + "intl-messageformat": "^11.1.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/valibot": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.2.tgz", + "integrity": "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-spinner": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.0.tgz", + "integrity": "sha512-Yw0hUB6UA3o4YUgKy3oSe9a4cxoaZ9sBfYDw+JSxo6Id0KoJGoxzPA24qqUXYKBWABs/zDSGTz9kww7t3F0XGw==", + "license": "MIT", + "dependencies": { + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18.19" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zeptomatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", + "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "grammex": "^3.1.11", + "graphmatch": "^1.1.0" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "license": "MIT", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1e48ae0 --- /dev/null +++ b/package.json @@ -0,0 +1,75 @@ +{ + "name": "isms-tool", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "check:guards": "tsx scripts/check-module-guards.ts", + "prebuild": "tsx scripts/check-module-guards.ts", + "build": "next build", + "start": "next start", + "lint": "eslint", + "worker:mail": "tsx scripts/mail-worker.ts", + "worker:backup": "tsx scripts/backup-worker.ts", + "worker:incident-inbound": "tsx scripts/incident-inbound-worker.ts", + "seed:content": "tsx prisma/seed-content.ts" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.115.0", + "@aws-sdk/client-s3": "^3.1103.0", + "@base-ui/react": "^1.6.0", + "@dagrejs/dagre": "^3.0.0", + "@dnd-kit/core": "^6.3.1", + "@node-rs/argon2": "^2.0.2", + "@prisma/adapter-pg": "^7.8.0", + "@prisma/client": "^7.8.0", + "@simplewebauthn/browser": "^9.0.1", + "@simplewebauthn/server": "^9.0.3", + "@xyflow/react": "^12.11.1", + "bullmq": "^6.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "dotenv": "^17.4.2", + "exceljs": "^4.4.0", + "handlebars": "^4.7.9", + "html-to-image": "^1.11.13", + "imapflow": "^1.7.1", + "ioredis": "^5.11.1", + "lucide-react": "^1.23.0", + "mailparser": "^3.9.15", + "marked": "^18.0.5", + "next": "16.2.12", + "next-auth": "5.0.0-beta.32", + "next-intl": "^4.13.1", + "nodemailer": "^8.0.11", + "otplib": "^13.4.1", + "qrcode": "^1.5.4", + "react": "19.2.4", + "react-dom": "19.2.4", + "sanitize-html": "^2.17.6", + "shadcn": "^4.12.0", + "tailwind-merge": "^3.6.0", + "tw-animate-css": "^1.4.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/nodemailer": "^8.0.1", + "@types/qrcode": "^1.5.6", + "@types/react": "^19", + "@types/react-dom": "^19", + "@types/sanitize-html": "^2.16.1", + "eslint": "^9", + "eslint-config-next": "16.2.12", + "prisma": "7.8.0", + "tailwindcss": "^4", + "tsx": "^4.22.4", + "typescript": "^5" + }, + "overrides": { + "postcss": "^8.5.25", + "sharp": "^0.35.3", + "valibot": "^1.4.2" + } +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/prisma.config.ts b/prisma.config.ts new file mode 100644 index 0000000..37c017f --- /dev/null +++ b/prisma.config.ts @@ -0,0 +1,13 @@ +import "dotenv/config"; +import { defineConfig, env } from "prisma/config"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + datasource: { + url: env("DATABASE_URL"), + }, + migrations: { + path: "prisma/migrations", + seed: "tsx prisma/seed.ts", + }, +}); diff --git a/prisma/import-hints.ts b/prisma/import-hints.ts new file mode 100644 index 0000000..3f25530 --- /dev/null +++ b/prisma/import-hints.ts @@ -0,0 +1,82 @@ +// Import der Umsetzungshinweise (Story B5-1) aus dem Fachcontent C6 in das globale +// Modell ImplementationHint. Ein Block je Teilanforderung: +// +// ### <id> — [<STUFE>] +// **Anforderung:** … +// - **Organisatorisch:** … +// - **Technisch:** … +// - **Typische Nachweise:** … +// - **Vorlage:** L00 +// - **Ressourcen:** … +// - **AL-Filter:** AL2 + AL3 +// +// Idempotent (Upsert über reqId). Kein tenantId (globaler Katalog). + +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import type { PrismaClient } from "@prisma/client"; + +const C6_PATH = join(__dirname, "..", "docs", "wizard-uebergabe", "02_Fachcontent_C1-C9", "C6_Umsetzungshinweise.md"); + +const field = (block: string, label: string): string => { + // Feldzeile "- **Label:** Wert" oder "**Label:** Wert" bis Zeilenende. + const re = new RegExp(`\\*\\*${label}:\\*\\*\\s*(.+)`); + const m = block.match(re); + return m ? m[1].trim() : ""; +}; + +const isProcurement = (resources: string): boolean => { + const r = resources.toLowerCase(); + if (/kein\s+toolbudget|kein\s+budget|ohne\s+budget|keine\s+beschaffung/.test(r)) return false; + return /beschaffung|toolbudget|budget|lizenz|invest|anschaffung|€|eur\b/.test(r); +}; + +export interface ParsedHint { + reqId: string; control: string; stufe: string; requirement: string; + organisational: string; technical: string; evidence: string; + template: string | null; resources: string; alFilter: string; procurement: boolean; +} + +/** Parst den C6-Text zu Hinweis-Objekten (ohne DB-Zugriff — testbar). */ +export function parseC6Hints(text: string): ParsedHint[] { + const hints: ParsedHint[] = []; + // Blöcke ab "### <id> — [STUFE]"; nächster "### "/"## "/"# " beendet den Block. + const re = /^###\s+(\S+)\s+—\s+\[([^\]]+)\]\s*\n([\s\S]*?)(?=^#{1,3}\s|$(?![\s\S]))/gm; + let m: RegExpExecArray | null; + while ((m = re.exec(text)) !== null) { + const reqId = m[1].trim(); + if (!/^\d+\.\d+\.\d+-/.test(reqId)) continue; // nur Anforderungs-IDs + const stufe = m[2].trim(); + const block = m[3]; + const resources = field(block, "Ressourcen"); + const template = field(block, "Vorlage") || null; + hints.push({ + reqId, + control: reqId.split("-")[0], + stufe, + requirement: field(block, "Anforderung"), + organisational: field(block, "Organisatorisch"), + technical: field(block, "Technisch"), + evidence: field(block, "Typische Nachweise"), + template, + resources, + alFilter: field(block, "AL-Filter"), + procurement: isProcurement(resources), + }); + } + return hints; +} + +/** Liest C6 und schreibt die Hinweise (Upsert je reqId). Liefert die Anzahl. */ +export async function importImplementationHints(prisma: PrismaClient): Promise<number> { + const text = readFileSync(C6_PATH, "utf-8"); + const hints = parseC6Hints(text); + for (const h of hints) { + await prisma.implementationHint.upsert({ + where: { reqId: h.reqId }, + update: { control: h.control, stufe: h.stufe, requirement: h.requirement, organisational: h.organisational, technical: h.technical, evidence: h.evidence, template: h.template, resources: h.resources, alFilter: h.alFilter, procurement: h.procurement }, + create: h, + }); + } + return hints.length; +} diff --git a/prisma/import-managed.ts b/prisma/import-managed.ts new file mode 100644 index 0000000..21a57cc --- /dev/null +++ b/prisma/import-managed.ts @@ -0,0 +1,222 @@ +import type { PrismaClient } from "@prisma/client"; + +/** + * Seed der verwalteten Register-Tabellen (§7b) und des Anwender-Handbuchs (§9.7). + * Defaults aus den Auftraggeber-Vorgaben FB-80-04 (Risikomatrix) und + * AA-80-20 (Klassifizierung/Handhabung). Idempotent pro Mandant. + */ + +const NOW = "2026-07-07T00:00:00.000Z"; +const daysFrom = (base: string, d: number) => new Date(new Date(base).getTime() + d * 86400000); + +// Klassifizierungs-Handhabungsmatrix (AA-80-20) — Reihenfolge: Offen · Intern · Vertraulich · Streng vertraulich +const CLASSES = [ + { name: "Offen", description: "Öffentlich; keine Schutzanforderungen." }, + { name: "Intern", description: "Nur für Mitarbeitende; geringer Schutzbedarf." }, + { name: "Vertraulich", description: "Begrenzter Personenkreis; hoher Schutzbedarf." }, + { name: "Streng vertraulich", description: "Namentlich Berechtigte; sehr hoher Schutzbedarf." }, +]; + +// [Offen, Intern, Vertraulich, Streng vertraulich] +const ASPECTS: { name: string; category: string; rules: [string, string, string, string] }[] = [ + { name: "Kennzeichnung (Papier/elektronisch)", category: "Kennzeichnung", rules: ["nicht nötig", "„Intern“ empfohlen", "„Vertraulich“ verpflichtend", "„Streng vertraulich“ + Bearbeiter"] }, + { name: "Vervielfältigung", category: "Handhabung", rules: ["frei", "im Bedarfsfall", "nur mit Freigabe", "nur mit Freigabe, protokolliert"] }, + { name: "Weitergabe intern", category: "Weitergabe", rules: ["frei", "an Mitarbeitende", "an Berechtigte, need-to-know", "namentlich Berechtigte, dokumentiert"] }, + { name: "Postweg / Versand", category: "Weitergabe", rules: ["Standard", "Standard", "verschlossen, persönlich/Einschreiben", "Einschreiben eigenhändig, Empfangsbestätigung"] }, + { name: "E-Mail", category: "Weitergabe", rules: ["ohne Auflagen", "intern ohne Auflagen", "extern verschlüsselt (BL-CRY-04)", "immer verschlüsselt, nur an Berechtigte"] }, + { name: "Fax intern/extern", category: "Weitergabe", rules: ["zulässig", "zulässig", "nur mit Ankündigung/Abholung", "unzulässig"] }, + { name: "Mobile Datenträger", category: "Speicherung", rules: ["zulässig", "nur freigegebene", "nur verschlüsselt (BL-CRY-03)", "nur verschlüsselt, freigegeben, protokolliert"] }, + { name: "Internet / Blogs / Social Media", category: "Weitergabe", rules: ["zulässig", "kein interner Bezug", "unzulässig", "unzulässig"] }, + { name: "Entsorgung Papier", category: "Entsorgung", rules: ["Altpapier", "Datentonne", "Aktenvernichter ≥ P-4", "Aktenvernichter ≥ P-5, protokolliert"] }, + { name: "Löschung elektronisch / Hardware", category: "Entsorgung", rules: ["normal löschen", "normal löschen", "sicheres Löschen (BL-DEL-01)", "sicheres Löschen/Vernichten, Nachweis"] }, + { name: "Speicherung (IT-Systeme)", category: "Speicherung", rules: ["beliebig", "interne Systeme", "zugriffsbeschränkte Ablagen", "verschlüsselt, streng zugriffsbeschränkt"] }, + { name: "Homeoffice / mobiles Arbeiten", category: "Nutzung", rules: ["zulässig", "zulässig", "nur mit Sichtschutz, gesperrt bei Abwesenheit", "nur nach Freigabe, keine Papierform"] }, + { name: "Öffentlicher Bereich / Dienstreise", category: "Nutzung", rules: ["zulässig", "diskret", "Sichtschutz, nicht unbeaufsichtigt", "unzulässig (kritische Länder)"] }, + { name: "Verbale Weitergabe", category: "Weitergabe", rules: ["frei", "unter Kollegen", "nur in geschützter Umgebung", "nur namentlich Berechtigte, abhörsicher"] }, +]; + +// Risiko-Bewertungsmatrix (FB-80-04): Schadensausmaß(1–4) × EW(1–4) = 1–16 +const RISK_CLASSES = [ + { name: "Niedrig", maxScore: 3, acceptance: "wird akzeptiert", tone: "ok" }, + { name: "Mittel", maxScore: 6, acceptance: "Maßnahmen; Akzeptanz durch Risk Owner", tone: "warn" }, + { name: "Hoch", maxScore: 9, acceptance: "Akzeptanz durch Risikomanagement-Gremium", tone: "orange" }, + { name: "Kritisch", maxScore: 16, acceptance: "Akzeptanz durch Geschäftsführung", tone: "risk" }, +]; +const EW_LEVELS = [ + { level: 1, label: "Unwahrscheinlich", definition: "Ereignis in absehbarer Zeit kaum zu erwarten (seltener als alle 5 Jahre)." }, + { level: 2, label: "Gelegentlich", definition: "Ereignis denkbar, aber nicht häufig (ca. alle 1–5 Jahre)." }, + { level: 3, label: "Wahrscheinlich", definition: "Ereignis tritt voraussichtlich ein (mehrmals pro Jahr)." }, + { level: 4, label: "Sehr wahrscheinlich", definition: "Ereignis tritt regelmäßig/häufig ein (monatlich oder öfter)." }, + { level: 5, label: "Nahezu sicher", definition: "Ereignis ist praktisch dauerhaft gegeben oder tritt ständig ein." }, +]; +const DAMAGE_DIMS: { name: string; levels: Record<string, string> }[] = [ + { name: "Gesetzes-/Vertragsverstöße", levels: { "1": "unerheblich", "2": "geringfügige Verstöße", "3": "erhebliche Verstöße/Bußgelder", "4": "gravierende Rechtsfolgen/Straftatbestand", "5": "existenzbedrohende Rechtsfolgen (Lizenzentzug/Haftung)" } }, + { name: "Datenschutz", levels: { "1": "kein Personenbezug", "2": "geringe Betroffenheit", "3": "sensible Daten betroffen", "4": "massenhaft sensible Daten / hohe Betroffenheit", "5": "besonders schützenswerte Daten in großem Umfang / existenzielle Betroffenheit" } }, + { name: "Persönliche Unversehrtheit", levels: { "1": "keine", "2": "leichte Beeinträchtigung", "3": "Gesundheitsgefahr", "4": "Gefahr für Leib und Leben", "5": "Lebensgefahr für viele / Todesfolge" } }, + { name: "Aufgabenerfüllung", levels: { "1": "keine Einschränkung", "2": "geringe Einschränkung", "3": "erhebliche Einschränkung", "4": "Kernaufgaben nicht erfüllbar", "5": "vollständiger, dauerhafter Ausfall der Organisation" } }, + { name: "Innen-/Außenwirkung (Reputation)", levels: { "1": "keine", "2": "intern begrenzt", "3": "öffentlich wahrnehmbar", "4": "nachhaltiger Reputationsschaden", "5": "existenzbedrohender, dauerhafter Reputationsverlust" } }, + { name: "Störungs-/Ausfallzeit", levels: { "1": "< 1 Std.", "2": "bis 1 Tag", "3": "bis 1 Woche", "4": "> 1 Woche", "5": "> 1 Monat / dauerhaft" } }, + { name: "Finanzielle Auswirkungen", levels: { "1": "bis 10 T€", "2": "bis 50 T€", "3": "bis 200 T€", "4": "über 500 T€", "5": "existenzbedrohend (> 1 Mio €)" } }, +]; + +// Krypto-Register (VA-07) — Demo-Datensätze inkl. Ablaufüberwachung +const CRYPTO = [ + { dienst: "TLS Web-Portal (portal.gefim.example)", schluessel: "RSA 3072 · Let's Encrypt", algorithmus: "TLS 1.3 / AES-256", ablaufOffset: 45, verantwortlich: "IT-Leitung", speicherort: "Reverse Proxy", baselineRef: "BL-CRY-01" }, + { dienst: "VPN-Gateway", schluessel: "ECDSA P-256 · interne CA", algorithmus: "IKEv2 / AES-256-GCM", ablaufOffset: 12, verantwortlich: "IT-Leitung", speicherort: "Firewall/HSM", baselineRef: "BL-CRY-02" }, + { dienst: "Festplattenverschlüsselung Notebooks", schluessel: "BitLocker · TPM 2.0", algorithmus: "AES-256-XTS", ablaufOffset: null, verantwortlich: "IT-Betrieb", speicherort: "MDM-Recovery", baselineRef: "BL-CRY-03" }, + { dienst: "S/MIME Zertifikate Geschäftsführung", schluessel: "RSA 2048 · öffentliche CA", algorithmus: "S/MIME", ablaufOffset: -8, verantwortlich: "IT-Leitung", speicherort: "Smartcard", baselineRef: "BL-CRY-04" }, +]; + +// Anwender-Handbuch (§9.7) — kuratierte Themen, Werte via {{VARIABLE}} synchron zur Baseline +const HANDBOOK: { category: string; title: string; bodyMd: string; sourceRefs: string[] }[] = [ + { + category: "Zugang & Passwörter", title: "Passwörter & Mehr-Faktor-Anmeldung", + bodyMd: "**Das Wichtigste kurz:**\n\n- Nutze Passwörter mit **mindestens {{PW_MIN_LENGTH}} Zeichen** ({{PW_COMPLEXITY}}).\n- Aktiviere **Mehr-Faktor-Authentifizierung (MFA)** über {{TECH_MFA}} für {{MFA_SCOPE}}.\n- Gib Passwörter **nie** weiter und nutze für jeden Dienst ein eigenes.\n- Bei Verdacht auf Kompromittierung: Passwort sofort ändern und melden.", + sourceRefs: ["R08#4.1.2"], + }, + { + category: "Zugang & Passwörter", title: "Zugriffsrechte – nur was du brauchst", + bodyMd: "- Zugriff erhältst du **nach dem Minimalprinzip** (need-to-know) über {{TOOL_TICKET}}.\n- Nicht mehr benötigte Rechte werden entzogen; deine Rechte werden regelmäßig **überprüft (Rezertifizierung, {{RECERT_FREQ}})**.\n- Sperre deinen Bildschirm bei jedem Verlassen des Arbeitsplatzes.", + sourceRefs: ["R08#4.2.1"], + }, + { + category: "Umgang mit Informationen", title: "Daten richtig klassifizieren & handhaben", + bodyMd: "- Behandle Informationen gemäß ihrer **Schutzklasse** (Offen · Intern · Vertraulich · Streng vertraulich).\n- **Vertrauliche** Inhalte extern nur **verschlüsselt** versenden.\n- Dokumente nicht offen liegen lassen (Clean Desk); vertrauliche Ausdrucke sicher vernichten.", + sourceRefs: ["R02"], + }, + { + category: "Sicheres Arbeiten", title: "Mobiles Arbeiten & Homeoffice", + bodyMd: "- Nutze nur **freigegebene Geräte** (verwaltet über {{TECH_MDM}}).\n- Achte auf **Sichtschutz** in der Öffentlichkeit; keine vertraulichen Gespräche in Bahn/Café.\n- Verbinde dich extern nur über {{TECH_VPN}} mit MFA.", + sourceRefs: ["R06"], + }, + { + category: "Sicheres Arbeiten", title: "E-Mail, Internet & Schadsoftware", + bodyMd: "- Öffne **keine unerwarteten Anhänge/Links**; im Zweifel nachfragen.\n- Melde verdächtige E-Mails (Phishing) über den Meldeweg.\n- {{TECH_MALWARE}} schützt deine Geräte – deaktiviere den Schutz nie.", + sourceRefs: ["R10", "R09"], + }, + { + category: "Vorfälle", title: "Sicherheitsvorfall? So meldest du ihn", + bodyMd: "**Sofort melden** bei Verdacht auf Vorfall, Datenverlust oder verlorenem Gerät:\n\n- an die {{ROLE_ISB}} bzw. den definierten Meldeweg.\n- Lieber einmal zu viel melden – schnelle Meldung begrenzt den Schaden.\n- Nichts vertuschen, nichts eigenmächtig „reparieren“.", + sourceRefs: ["R04"], + }, +]; + +/** Generische verwaltete Register (WP3.0): Code, Titel, Pflichtspalten, Cross-Links. */ +const GENERIC_REGISTERS: { + code: string; title: string; description: string; orderIdx: number; + columns: { key: string; label: string }[]; supplierLink?: boolean; assetLink?: boolean; +}[] = [ + { code: "REG-PROJECTS", title: "Register Informationssicherheit in Projekten", orderIdx: 905, + description: "Projekte mit IS-Klassifizierung, Risikobewertung, Maßnahmen und ISB-Einbindung (R01 / VA-19).", + columns: [{ key: "projekt", label: "Projekt" }, { key: "klassifizierung", label: "IS-Klassifizierung" }, { key: "risiko", label: "Risikobewertung" }, { key: "massnahmen", label: "Maßnahmen/Status" }, { key: "isb", label: "ISB-Einbindung" }] }, + { code: "REG-SENS-ROLES", title: "Register sensibler Tätigkeiten", orderIdx: 906, + description: "Sensible Tätigkeitsbereiche/Rollen mit Eignungsnachweisen und Prüftiefe (R05 / VA-14).", + columns: [{ key: "rolle", label: "Rolle/Bereich" }, { key: "nachweise", label: "Geforderte Eignungsnachweise" }, { key: "prueftiefe", label: "Prüftiefe" }, { key: "verantwortlich", label: "Verantwortlich" }, { key: "review", label: "Review" }] }, + { code: "REG-AUDIT-PLAN", title: "Audit-Programm-Register", orderIdx: 907, + description: "Auditprogramm mit Zeitplan, Umfang, geprüften Controls, Prüfern und Ergebnissen (R03 / VA-15).", + columns: [{ key: "zeitplan", label: "Zeitplan" }, { key: "umfang", label: "Umfang" }, { key: "controls", label: "Geprüfte Controls" }, { key: "pruefer", label: "Prüfer" }, { key: "ergebnisse", label: "Ergebnisse" }] }, + // REG-NET bleibt ein leichtgewichtiges Register: der Netzplan ist ein extern gepflegtes + // Dokument, daher nur Referenz/Speicherort statt Tabelleninhalt (Datei-Upload folgt separat). + { code: "REG-NET", title: "Netz-/Netzdienste-Register", orderIdx: 911, + description: "Verweis auf den (extern gepflegten) Netzplan sowie Netzdienste/Zonen und Review-Turnus (R09 5.1.2 / R10 5.2.7 / VA-07).", + columns: [{ key: "netzplan", label: "Netzplan (Speicherort/Referenz)" }, { key: "netzdienst", label: "Netzdienst" }, { key: "zone", label: "Zone" }, { key: "review", label: "Review" }] }, +]; + +// GAP-Konsolidierung: Diese Register wurden in die Fachmodule überführt und werden +// daher stillgelegt (Dokument + ManagedRegister + Zeilen entfernt). Die zugehörigen +// {{LINK:…}} zeigen jetzt auf die Module (siehe resolveLink): +// REG-EXT-SERVICES → Lieferanten/IT-Services · REG-SW-WHITELIST → Lieferanten/Software +// REG-CRIT-SERVICES → Assets (kritische Dienste) · REG-PROJECTS → Assets (Projekte) +const RETIRED_REGISTERS = ["REG-EXT-SERVICES", "REG-SW-WHITELIST", "REG-CRIT-SERVICES", "REG-PROJECTS"]; + +export async function importManaged(prisma: PrismaClient, tenantId: string) { + // Idempotent: alte Datensätze pro Mandant entfernen + await prisma.handlingRule.deleteMany({ where: { tenantId } }); + await prisma.handlingAspect.deleteMany({ where: { tenantId } }); + await prisma.classificationClass.deleteMany({ where: { tenantId } }); + await prisma.cryptoEntry.deleteMany({ where: { tenantId } }); + await prisma.riskMatrixClass.deleteMany({ where: { tenantId } }); + await prisma.riskEwLevel.deleteMany({ where: { tenantId } }); + await prisma.riskDamageDimension.deleteMany({ where: { tenantId } }); + await prisma.handbookTopic.deleteMany({ where: { tenantId } }); + + // Register-/Handbuch-Dokumente in der Bibliothek (interaktiv gerendert) + const registerDocs = [ + { code: "CRYPTO", type: "REGISTER" as const, title: "Verschlüsselungsmechanismen-Register", orderIdx: 902, intro: "Verwaltetes Register der eingesetzten Verschlüsselung (VA-07). Ablaufüberwachung aktiv." }, + { code: "RISKMATRIX", type: "REGISTER" as const, title: "Risiko-Bewertungsmatrix", orderIdx: 903, intro: "Zentrale Bewertungsmatrix Schadensausmaß × Eintrittswahrscheinlichkeit (R03 / VA-09), Defaults nach FB-80-04." }, + { code: "CLASSIFICATION", type: "REGISTER" as const, title: "Klassifizierung & Handhabungsmatrix", orderIdx: 904, intro: "Schutzklassen und Handhabungsregeln (R02 / VA-08), Defaults nach AA-80-20." }, + { code: "HANDBUCH", type: "HANDBUCH" as const, title: "Anwender-Handbuch Informationssicherheit", orderIdx: 950, intro: "Kompakte Zusammenfassung der wichtigsten Regeln für Mitarbeitende – mit Deep-Links in die Quelldokumente." }, + ]; + for (const d of registerDocs) { + await prisma.policyDocument.upsert({ + where: { tenantId_code: { tenantId, code: d.code } }, + update: { title: d.title, type: d.type, orderIdx: d.orderIdx, rawMarkdown: `# ${d.title}\n\n${d.intro}` }, + create: { tenantId, code: d.code, type: d.type, title: d.title, version: "1.0", status: "FREIGEGEBEN", orderIdx: d.orderIdx, rawMarkdown: `# ${d.title}\n\n${d.intro}` }, + }); + } + + // Generische verwaltete Register (GAP-Report WP3.0 / §5.2): Dokument (Bibliothek/Link) + // + editierbare ManagedRegister-Definition mit Pflichtspalten + Cross-Links. Zeilen + // (RegisterRow) bleiben bei Re-Import erhalten (nicht-destruktiv). + for (const g of GENERIC_REGISTERS) { + const intro = `${g.description} Pflichtspalten: ${g.columns.map((c) => c.label).join(", ")}.`; + await prisma.policyDocument.upsert({ + where: { tenantId_code: { tenantId, code: g.code } }, + update: { title: g.title, type: "REGISTER", orderIdx: g.orderIdx, rawMarkdown: `# ${g.title}\n\n${intro}` }, + create: { tenantId, code: g.code, type: "REGISTER", title: g.title, version: "1.0", status: "FREIGEGEBEN", orderIdx: g.orderIdx, rawMarkdown: `# ${g.title}\n\n${intro}` }, + }); + await prisma.managedRegister.upsert({ + where: { tenantId_code: { tenantId, code: g.code } }, + update: { title: g.title, description: g.description, columns: g.columns, supplierLink: g.supplierLink ?? false, assetLink: g.assetLink ?? false }, + create: { tenantId, code: g.code, title: g.title, description: g.description, columns: g.columns, supplierLink: g.supplierLink ?? false, assetLink: g.assetLink ?? false }, + }); + } + + // Stillgelegte Register entfernen (in Fachmodule überführt). RegisterRow hängt per + // Cascade an ManagedRegister; das Bibliotheks-Dokument wird ebenfalls entfernt. + await prisma.managedRegister.deleteMany({ where: { tenantId, code: { in: RETIRED_REGISTERS } } }); + await prisma.policyDocument.deleteMany({ where: { tenantId, code: { in: RETIRED_REGISTERS } } }); + + // Krypto-Register + for (let i = 0; i < CRYPTO.length; i++) { + const c = CRYPTO[i]; + await prisma.cryptoEntry.create({ + data: { + tenantId, dienst: c.dienst, schluessel: c.schluessel, algorithmus: c.algorithmus, + ablaufdatum: c.ablaufOffset === null ? null : daysFrom(NOW, c.ablaufOffset), + verantwortlich: c.verantwortlich, speicherort: c.speicherort, baselineRef: c.baselineRef, orderIdx: i, + }, + }); + } + + // Klassifizierung + Handhabungsmatrix + const classIds: string[] = []; + for (let i = 0; i < CLASSES.length; i++) { + const cl = await prisma.classificationClass.create({ data: { tenantId, name: CLASSES[i].name, description: CLASSES[i].description, orderIdx: i } }); + classIds.push(cl.id); + } + for (let a = 0; a < ASPECTS.length; a++) { + const asp = await prisma.handlingAspect.create({ data: { tenantId, name: ASPECTS[a].name, category: ASPECTS[a].category, orderIdx: a } }); + for (let c = 0; c < classIds.length; c++) { + await prisma.handlingRule.create({ data: { tenantId, classId: classIds[c], aspectId: asp.id, text: ASPECTS[a].rules[c] } }); + } + } + + // Risiko-Bewertungsmatrix + for (let i = 0; i < RISK_CLASSES.length; i++) { + const r = RISK_CLASSES[i]; + await prisma.riskMatrixClass.create({ data: { tenantId, name: r.name, maxScore: r.maxScore, acceptance: r.acceptance, tone: r.tone, orderIdx: i } }); + } + for (const ew of EW_LEVELS) await prisma.riskEwLevel.create({ data: { tenantId, level: ew.level, label: ew.label, definition: ew.definition } }); + for (let i = 0; i < DAMAGE_DIMS.length; i++) { + await prisma.riskDamageDimension.create({ data: { tenantId, name: DAMAGE_DIMS[i].name, levels: DAMAGE_DIMS[i].levels, orderIdx: i } }); + } + + // Anwender-Handbuch + for (let i = 0; i < HANDBOOK.length; i++) { + const h = HANDBOOK[i]; + await prisma.handbookTopic.create({ data: { tenantId, category: h.category, title: h.title, bodyMd: h.bodyMd, sourceRefs: h.sourceRefs, orderIdx: i } }); + } + + return { crypto: CRYPTO.length, classes: CLASSES.length, aspects: ASPECTS.length, damage: DAMAGE_DIMS.length, handbook: HANDBOOK.length }; +} diff --git a/prisma/import-policies.ts b/prisma/import-policies.ts new file mode 100644 index 0000000..8d0457e --- /dev/null +++ b/prisma/import-policies.ts @@ -0,0 +1,521 @@ +import { readFileSync, readdirSync } from "node:fs"; +import { join } from "node:path"; +import type { PrismaClient, Framework } from "@prisma/client"; + +/** + * Mapping-Datei je Framework (AP1). Beide Frameworks teilen sich denselben + * Dokumentensatz (richtlinien/, verfahren/, Baseline, Nachweisregister); nur die + * Anforderungs-Zuordnung unterscheidet sich → nur der Mapping-Dateiname wechselt + * (Variante A). Default TISAX, damit Bestandsaufrufer unverändert bleiben. + */ +export function mappingFileFor(framework: Framework = "TISAX"): string { + return framework === "ISO_27001" ? "mapping-iso.json" : "mapping.json"; +} + +/** Kanonische Version des Vorlagenpakets (mapping meta.version) — Story B6. */ +export function readPackageVersion(seedDir: string, mappingFile = "mapping.json"): string { + const mapping = JSON.parse(readFileSync(join(seedDir, mappingFile), "utf-8")) as { meta?: { version?: string } }; + return mapping.meta?.version ?? "unknown"; +} + +/** Übernommene Paket-Version je Mandant/Framework stempeln (Story B6) — nach jedem Apply. */ +export async function stampPackageState( + prisma: PrismaClient, + tenantId: string, + seedDir: string, + framework: Framework = "TISAX", +): Promise<void> { + await stampPackageVersion(prisma, tenantId, readPackageVersion(seedDir, mappingFileFor(framework)), framework); +} + +/** Wie stampPackageState, aber mit direkt übergebener Version (DB-Vorlagen-Quelle). */ +export async function stampPackageVersion( + prisma: PrismaClient, + tenantId: string, + version: string, + framework: Framework = "TISAX", +): Promise<void> { + await prisma.policyPackageState.upsert({ + where: { tenantId_framework: { tenantId, framework } }, + update: { importedVersion: version, importedAt: new Date() }, + create: { tenantId, framework, importedVersion: version, importedAt: new Date() }, + }); +} + +/** + * Importer für das VDA-ISA-2027-Vorlagenpaket (§6 der Spezifikation). + * + * Das Modul ist in zwei Schritte getrennt: + * 1. `parsePackageFiles(seedDir)` — liest die echten .md-Dateien, mapping.json, + * variables.schema.json, Technische-Sicherheits-Baseline.md und + * Nachweisregister_zentral.md in ein neutrales `ParsedPackage`. + * 2. `reconcilePackage(prisma, tenantId, pkg)` — schreibt ein `ParsedPackage` + * **nicht-destruktiv** in die Mandanten-Tabellen (Diff/Upsert). + * Dieselbe `ParsedPackage`-Struktur kommt auch aus der globalen DB-Vorlagenablage + * (template-store.ts), sodass der Reconcile-Import identisch für Datei- UND + * DB-Quelle funktioniert. + * + * **Nicht-destruktiver Re-Import (Phase-1-Härtung Paket 3):** Abgleich über stabile + * Schlüssel (Dokument-`code`, Anforderungs-`reqId`, Variablen-`key`, Baseline-`blId`, + * Nachweis-`nr`) per Diff/Upsert statt Löschen+Neuanlegen. + * - Neu im Paket ⇒ anlegen. + * - Weiterhin vorhanden ⇒ Inhalt aktualisieren, aber per-Dokument-Status, + * TISAX-Override, Freigabe-/Versionsstand und Verknüpfungen (Coverage/Nachweise) + * sowie **nutzergepflegte Variablenwerte** erhalten. + * - Nicht mehr im Paket ⇒ **deaktivieren** (`archivedAt` setzen), nicht löschen. + * Jeder Lauf liefert einen Änderungsreport (added/updated/archived/reactivated) und + * protokolliert ihn im Audit-Log. `dryRun` erzeugt den Report ohne Schreibzugriffe + * (Vorschau). Idempotent: erneuter Lauf ohne Änderungen ⇒ nur „unchanged". + */ + +type DocType = "LEITLINIE" | "RICHTLINIE" | "VERFAHREN" | "REGISTER"; + +const arraysEqual = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i]); + +// ── Neutrale Paket-Struktur (Quelle: Dateien ODER globale DB-Vorlagenablage) ────── +export interface ParsedDoc { + code: string; + type: DocType; + title: string; + policyCode: string | null; + fulfills: string[]; + rawMarkdown: string; + orderIdx: number; +} +export interface ParsedRequirement { + reqId: string; + policyCode: string; + control: string; + obligation: string; + condition: string | null; + requirement: string; + implementation: string; + vaCodes: string[]; + nachweisLink: string | null; +} +export interface ParsedVariable { + key: string; + title: string; + kind: string; + groupName: string | null; + value: string; + required: boolean; + orderIdx: number; +} +export interface ParsedBaselineParam { + blId: string; + section: string; + name: string; + vorgabe: string; + orderIdx: number; +} +export interface ParsedEvidence { + nr: number; + policyCode: string; + nachweis: string; + quelle: string; + verantwortlich: string; + turnus: string; +} +export interface ParsedPackage { + version: string; + documents: ParsedDoc[]; + requirements: ParsedRequirement[]; + variables: ParsedVariable[]; + baseline: ParsedBaselineParam[]; + evidence: ParsedEvidence[]; +} + +/** + * Namensraum der Dokumente, die DIESER Importer verwaltet (Leitlinie, Richtlinien, + * Verfahren, Baseline-/Nachweisregister). Verwaltete Register aus import-managed.ts + * (CRYPTO, RISKMATRIX, CLASSIFICATION, HANDBUCH, …) gehören NICHT dazu und dürfen beim + * Re-Import nicht deaktiviert werden. + */ +const isPackageDoc = (code: string) => + code === "L00" || code === "BASELINE" || code === "NACHWEIS" || /^R\d/.test(code) || /^VA-/.test(code); + +function docCodeFromFile(file: string): string { + return file.split("_")[0]; // "R08_…​.md" → "R08", "VA-03_…​.md" → "VA-03" +} +function titleOf(md: string): string { + const m = md.match(/^#\s+(.+?)\s*$/m); + return m ? m[1].trim() : "(ohne Titel)"; +} +/** Umsetzungstext je Anforderung aus den `<!-- IMPL id -->`-Ankern extrahieren. */ +function extractImpls(raw: string, into: Map<string, string>) { + const lines = raw.split("\n"); + for (let i = 0; i < lines.length; i++) { + const m = lines[i].match(/^<!--\s*IMPL\s+(\S+)\s*-->/); + if (!m) continue; + const buf: string[] = []; + for (let j = i + 1; j < lines.length; j++) { + const l = lines[j]; + const tr = l.trim(); + if (tr === "" || tr.startsWith("<!--") || tr.startsWith("{{#") || tr.startsWith("{{/") || /^#{1,6}\s/.test(tr) || tr.startsWith("**") || tr.startsWith("- ") || tr.startsWith("|")) break; + buf.push(l); + } + if (buf.length) into.set(m[1], buf.join(" ").trim()); + } +} + +function varGroup(key: string): string { + if (key.startsWith("FLAG_")) return "Feature-Flags"; + if (key.startsWith("ORG_") || key.startsWith("ISMS_")) return "Organisation"; + if (key.startsWith("ROLE_")) return "Rollen"; + if (key.startsWith("DOC_")) return "Metadaten"; + if (key.startsWith("TECH_") || key.startsWith("TOOL_")) return "Technik/Werkzeuge"; + if (/^(PW_|MFA_|SESSION_|ACCOUNT_|RECERT_)/.test(key)) return "IAM-Baseline"; + if (key.startsWith("TLS_") || key.startsWith("CRYPTO_")) return "Krypto-Baseline"; + if (/^(PATCH_|VULN_|MALWARE_|LOG_|BACKUP_|PENTEST_)/.test(key)) return "Betriebs-Baseline"; + return "Sonstige"; +} + +interface SchemaProp { + type?: string; + title?: string; + default?: string | boolean; + example?: string; +} + +export interface ImportReport { + documents: { added: number; updated: number; archived: number; reactivated: number; unchanged: number }; + requirements: { added: number; updated: number; archived: number; reactivated: number; unchanged: number }; + variables: { added: number; updated: number; unchanged: number; obsolete: number }; + baseline: { added: number; updated: number; unchanged: number; obsolete: number }; + evidence: { added: number; updated: number; unchanged: number; obsolete: number }; +} + +export interface ImportOptions { + /** true = nur Report berechnen, keine Schreibzugriffe (Vorschau). */ + dryRun?: boolean; + /** Akteur für den Audit-Eintrag (z. B. Plattform-/Mandanten-Admin). */ + actorId?: string | null; + /** + * Namensraum der abzugleichenden Anforderungen (AP1). Der Archivierungslauf und die + * Anlage laufen NUR innerhalb dieses Frameworks — ein ISO-Import archiviert damit + * keine TISAX-Anforderungen (und umgekehrt, Falle 1.1). Default TISAX. + */ + framework?: Framework; + /** + * Geteilte Inhalte (Dokumente, Variablen, Baseline, Nachweisregister) mit abgleichen. + * Diese sind für beide Frameworks identisch und dürfen je Mandant **einmal** + * abgeglichen werden (Falle 1.1). Beim Import mehrerer Frameworks nur für das erste + * `true` setzen. Default true (Einzel-Framework-Fall unverändert). + */ + reconcileShared?: boolean; +} + +/** + * Liest das Datei-Vorlagenpaket in eine neutrale `ParsedPackage`-Struktur (kein DB-Zugriff). + * Quelle für die einmalige Synchronisierung in die globale DB-Vorlagenablage und für den + * Datei-Fallback des Mandanten-Imports. + */ +export function parsePackageFiles(seedDir: string, mappingFile = "mapping.json"): ParsedPackage { + // ── 1. mapping-Datei → Anforderungen + FULFILLS-Rückwärtsmapping vorbereiten ── + const mapping = JSON.parse(readFileSync(join(seedDir, mappingFile), "utf-8")) as { + meta?: { version?: string }; + anforderungen: Array<{ + id: string; policy: string; control: string; type: string; + condition: string | null; requirement: string; implementation?: string; nachweis_link?: string; + /** Optional: „IMPL <key>" — Umsetzungsblock, aus dem der Text stammt (Control- statt Anforderungsebene). */ + impl_anchor?: string; + }>; + }; + const version = mapping.meta?.version ?? "unknown"; + + // ── 2. Dokumente einlesen (Richtlinien + Verfahren) ────────────────────── + const reqToVas = new Map<string, Set<string>>(); + const implMap = new Map<string, string>(); // Umsetzungstext je Anforderung aus den IMPL-Ankern + const documents: ParsedDoc[] = []; + + const richtDir = join(seedDir, "richtlinien"); + for (const file of readdirSync(richtDir).filter((f) => f.endsWith(".md")).sort()) { + const raw = readFileSync(join(richtDir, file), "utf-8"); + const code = docCodeFromFile(file); + const type: DocType = code === "L00" ? "LEITLINIE" : "RICHTLINIE"; + const orderIdx = code === "L00" ? 0 : parseInt(code.replace(/\D/g, ""), 10); + extractImpls(raw, implMap); + documents.push({ code, type, title: titleOf(raw), policyCode: null, fulfills: [], rawMarkdown: raw, orderIdx }); + } + + const verfDir = join(seedDir, "verfahren"); + for (const file of readdirSync(verfDir).filter((f) => f.endsWith(".md")).sort()) { + const raw = readFileSync(join(verfDir, file), "utf-8"); + const code = docCodeFromFile(file); + const fh = raw.match(/<!--\s*FULFILLS\s+([^|]+?)\s*\|\s*POLICY\s+(\S+)\s*-->/); + const fulfills = fh ? fh[1].split(",").map((s) => s.trim()).filter(Boolean) : []; + const policyCode = fh ? fh[2].trim() : null; + for (const req of fulfills) { + if (!reqToVas.has(req)) reqToVas.set(req, new Set()); + reqToVas.get(req)!.add(code); + } + const orderIdx = 100 + parseInt(code.replace(/\D/g, ""), 10); + documents.push({ code, type: "VERFAHREN", title: titleOf(raw), policyCode, fulfills, rawMarkdown: raw, orderIdx }); + } + + // Register-Dokumente (Baseline + Nachweisregister) mitführen + const baselineRaw = readFileSync(join(seedDir, "Technische-Sicherheits-Baseline.md"), "utf-8"); + const nachweisRaw = readFileSync(join(seedDir, "Nachweisregister_zentral.md"), "utf-8"); + documents.push({ code: "BASELINE", type: "REGISTER", title: titleOf(baselineRaw), policyCode: null, fulfills: [], rawMarkdown: baselineRaw, orderIdx: 900 }); + documents.push({ code: "NACHWEIS", type: "REGISTER", title: titleOf(nachweisRaw), policyCode: null, fulfills: [], rawMarkdown: nachweisRaw, orderIdx: 901 }); + + // ── 3. Anforderungen ───────────────────────────────────────────────────── + // Umsetzungstext: bevorzugt über `impl_anchor` (Control-Ebene, z. B. „IMPL 4.1.2") auflösen — + // die Anforderungs-IDs (4.1.2-M1) haben keinen eigenen IMPL-Block. Fällt zurück auf die + // Anforderungs-ID und zuletzt auf ein im Mapping mitgeliefertes `implementation`-Feld. + const implOf = (a: { id: string; impl_anchor?: string; implementation?: string }) => + implMap.get((a.impl_anchor ?? "").replace(/^IMPL\s+/, "")) ?? implMap.get(a.id) ?? a.implementation ?? ""; + + const requirements: ParsedRequirement[] = mapping.anforderungen.map((a) => ({ + reqId: a.id, policyCode: a.policy, control: a.control, obligation: a.type, + condition: a.condition, requirement: a.requirement, implementation: implOf(a), + vaCodes: [...(reqToVas.get(a.id) ?? [])].sort(), nachweisLink: a.nachweis_link ?? null, + })); + + // ── 4. Variablen + Feature-Flags ───────────────────────────────────────── + const schema = JSON.parse(readFileSync(join(seedDir, "variables.schema.json"), "utf-8")) as { + properties: Record<string, SchemaProp>; required?: string[]; + }; + const required = new Set(schema.required ?? []); + const variables: ParsedVariable[] = Object.entries(schema.properties).map(([key, prop], i) => { + const kind = prop.type === "boolean" ? "boolean" : "string"; + const value = prop.default !== undefined ? String(prop.default) : prop.example !== undefined ? String(prop.example) : kind === "boolean" ? "false" : ""; + return { key, title: prop.title ?? key, kind, groupName: varGroup(key), value, required: required.has(key), orderIdx: i }; + }); + + // ── 5. Baseline-Parameter ──────────────────────────────────────────────── + const baseline: ParsedBaselineParam[] = []; + { + let section = ""; + let bi = 0; + for (const line of baselineRaw.split("\n")) { + const h = line.match(/^##\s+(.+?)\s*$/); + if (h) { section = h[1].trim(); continue; } + const row = line.match(/^\|\s*(BL-[A-Z]+-\d+)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*$/); + if (row) baseline.push({ blId: row[1], section, name: row[2].trim(), vorgabe: row[3].trim(), orderIdx: bi++ }); + } + } + + // ── 6. Nachweisregister ────────────────────────────────────────────────── + const evidence: ParsedEvidence[] = []; + for (const line of nachweisRaw.split("\n")) { + const row = line.match(/^\|\s*(\d+)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*$/); + if (!row) continue; + const policyMatch = row[2].match(/\{\{LINK:([^}]+)\}\}/); + evidence.push({ + nr: parseInt(row[1], 10), policyCode: policyMatch ? policyMatch[1] : row[2].trim(), + nachweis: row[3].trim(), quelle: row[4].trim(), verantwortlich: row[5].trim(), turnus: row[6].trim(), + }); + } + + return { version, documents, requirements, variables, baseline, evidence }; +} + +/** + * Schreibt ein `ParsedPackage` nicht-destruktiv in die Mandanten-Tabellen (Diff/Upsert). + * Quelle-neutral: das Paket stammt aus den Dateien (`parsePackageFiles`) oder der globalen + * DB-Vorlagenablage (`loadPublishedPackage`). + */ +export async function reconcilePackage( + prisma: PrismaClient, + tenantId: string, + pkg: ParsedPackage, + options: ImportOptions = {} +) { + const dryRun = options.dryRun ?? false; + const framework: Framework = options.framework ?? "TISAX"; + // Geteilte Inhalte (Dokumente/Variablen/Baseline/Nachweise) sind frameworkübergreifend + // identisch → nur einmal je Mandant abgleichen (Falle 1.1). Anforderungen dagegen + // IMMER, aber framework-scoped. + const reconcileShared = options.reconcileShared ?? true; + const now = new Date(); + const report: ImportReport = { + documents: { added: 0, updated: 0, archived: 0, reactivated: 0, unchanged: 0 }, + requirements: { added: 0, updated: 0, archived: 0, reactivated: 0, unchanged: 0 }, + variables: { added: 0, updated: 0, unchanged: 0, obsolete: 0 }, + baseline: { added: 0, updated: 0, unchanged: 0, obsolete: 0 }, + evidence: { added: 0, updated: 0, unchanged: 0, obsolete: 0 }, + }; + + // ── Reconcile Dokumente (Upsert über code; Status/Override/Freigabe bleiben) ── + // Geteilt → nur beim ersten Framework je Mandant (Falle 1.1). + if (reconcileShared) { + const existingDocs = await prisma.policyDocument.findMany({ where: { tenantId } }); + const docByCode = new Map(existingDocs.map((d) => [d.code, d])); + const desiredDocCodes = new Set(pkg.documents.map((d) => d.code)); + for (const d of pkg.documents) { + const ex = docByCode.get(d.code); + if (!ex) { + report.documents.added++; + if (!dryRun) + await prisma.policyDocument.create({ + data: { + tenantId, code: d.code, type: d.type, title: d.title, version: "1.0", status: "FREIGEGEBEN", + policyCode: d.policyCode, fulfills: d.fulfills, rawMarkdown: d.rawMarkdown, orderIdx: d.orderIdx, + }, + }); + continue; + } + const contentChanged = + ex.type !== d.type || ex.title !== d.title || (ex.policyCode ?? null) !== (d.policyCode ?? null) || + !arraysEqual(ex.fulfills, d.fulfills) || ex.rawMarkdown !== d.rawMarkdown || ex.orderIdx !== d.orderIdx; + // Nur Inhaltsfelder + Lifecycle; Status/Version/Owner/Freigabe/Override NICHT anfassen. + const contentData = { type: d.type, title: d.title, policyCode: d.policyCode, fulfills: d.fulfills, rawMarkdown: d.rawMarkdown, orderIdx: d.orderIdx }; + if (ex.archivedAt) { + report.documents.reactivated++; + if (!dryRun) await prisma.policyDocument.update({ where: { id: ex.id }, data: { ...contentData, archivedAt: null } }); + } else if (contentChanged) { + report.documents.updated++; + if (!dryRun) await prisma.policyDocument.update({ where: { id: ex.id }, data: contentData }); + } else { + report.documents.unchanged++; + } + } + for (const ex of existingDocs) { + // Nur Paket-Dokumente deaktivieren — verwaltete Register (import-managed) unberührt lassen. + if (desiredDocCodes.has(ex.code) || ex.archivedAt || !isPackageDoc(ex.code)) continue; + report.documents.archived++; + if (!dryRun) await prisma.policyDocument.update({ where: { id: ex.id }, data: { archivedAt: now } }); + } + } // Ende reconcileShared (Dokumente) + + // ── Reconcile Anforderungen (Upsert über reqId; entfernte deaktiviert) — FRAMEWORK-SCOPED ── + // Nur Anforderungen DIESES Frameworks lesen/anlegen/archivieren, damit ein ISO-Import + // die TISAX-Anforderungen (und umgekehrt) nicht stilllegt (Falle 1.1). + const existingReqs = await prisma.policyRequirement.findMany({ where: { tenantId, framework } }); + const reqById = new Map(existingReqs.map((r) => [r.reqId, r])); + const desiredReqIds = new Set(pkg.requirements.map((r) => r.reqId)); + for (const r of pkg.requirements) { + const ex = reqById.get(r.reqId); + if (!ex) { + report.requirements.added++; + if (!dryRun) await prisma.policyRequirement.create({ data: { tenantId, framework, ...r } }); + continue; + } + const changed = + ex.policyCode !== r.policyCode || ex.control !== r.control || ex.obligation !== r.obligation || + (ex.condition ?? null) !== (r.condition ?? null) || ex.requirement !== r.requirement || + ex.implementation !== r.implementation || !arraysEqual(ex.vaCodes, r.vaCodes) || + (ex.nachweisLink ?? null) !== (r.nachweisLink ?? null); + if (ex.archivedAt) { + report.requirements.reactivated++; + if (!dryRun) await prisma.policyRequirement.update({ where: { id: ex.id }, data: { ...r, archivedAt: null } }); + } else if (changed) { + report.requirements.updated++; + if (!dryRun) await prisma.policyRequirement.update({ where: { id: ex.id }, data: r }); + } else { + report.requirements.unchanged++; + } + } + for (const ex of existingReqs) { + if (desiredReqIds.has(ex.reqId) || ex.archivedAt) continue; + report.requirements.archived++; + if (!dryRun) await prisma.policyRequirement.update({ where: { id: ex.id }, data: { archivedAt: now } }); + } + + // Geteilte Inhalte (Variablen/Baseline/Nachweise) wieder nur beim ersten Framework. + if (reconcileShared) { + // ── Reconcile Variablen + Feature-Flags (Wert bleibt IMMER erhalten) ── + const existingVars = await prisma.policyVariable.findMany({ where: { tenantId } }); + const varByKey = new Map(existingVars.map((v) => [v.key, v])); + const desiredVarKeys = new Set(pkg.variables.map((v) => v.key)); + for (const v of pkg.variables) { + const ex = varByKey.get(v.key); + if (!ex) { + report.variables.added++; + if (!dryRun) await prisma.policyVariable.create({ data: { tenantId, ...v } }); + continue; + } + // Nur Metadaten aktualisieren — den (ggf. vom Kunden gepflegten) value NIE überschreiben. + const metaChanged = + ex.title !== v.title || ex.kind !== v.kind || (ex.groupName ?? null) !== (v.groupName ?? null) || + ex.required !== v.required || ex.orderIdx !== v.orderIdx; + if (metaChanged) { + report.variables.updated++; + if (!dryRun) await prisma.policyVariable.update({ where: { id: ex.id }, data: { title: v.title, kind: v.kind, groupName: v.groupName, required: v.required, orderIdx: v.orderIdx } }); + } else { + report.variables.unchanged++; + } + } + // Nicht mehr im Schema enthaltene Variablen bleiben bestehen (können in eigenem + // Rohtext referenziert sein) — nur als „obsolet" im Report ausgewiesen. + report.variables.obsolete = existingVars.filter((v) => !desiredVarKeys.has(v.key)).length; + + // ── Reconcile Baseline-Parameter (Upsert über blId) ─────────────────── + const existingBaseline = await prisma.policyBaselineParam.findMany({ where: { tenantId } }); + const blById = new Map(existingBaseline.map((b) => [b.blId, b])); + const desiredBlIds = new Set(pkg.baseline.map((b) => b.blId)); + for (const b of pkg.baseline) { + const ex = blById.get(b.blId); + if (!ex) { + report.baseline.added++; + if (!dryRun) await prisma.policyBaselineParam.create({ data: { tenantId, ...b } }); + continue; + } + const changed = ex.section !== b.section || ex.name !== b.name || ex.vorgabe !== b.vorgabe || ex.orderIdx !== b.orderIdx; + if (changed) { + report.baseline.updated++; + if (!dryRun) await prisma.policyBaselineParam.update({ where: { id: ex.id }, data: { section: b.section, name: b.name, vorgabe: b.vorgabe, orderIdx: b.orderIdx } }); + } else { + report.baseline.unchanged++; + } + } + report.baseline.obsolete = existingBaseline.filter((b) => !desiredBlIds.has(b.blId)).length; + + // ── Reconcile Nachweisregister (Upsert über nr) ─────────────────────── + const existingEvidence = await prisma.policyEvidence.findMany({ where: { tenantId } }); + const evByNr = new Map(existingEvidence.map((e) => [e.nr, e])); + const desiredNrs = new Set(pkg.evidence.map((e) => e.nr)); + for (const e of pkg.evidence) { + const ex = evByNr.get(e.nr); + if (!ex) { + report.evidence.added++; + if (!dryRun) await prisma.policyEvidence.create({ data: { tenantId, ...e } }); + continue; + } + const changed = ex.policyCode !== e.policyCode || ex.nachweis !== e.nachweis || ex.quelle !== e.quelle || ex.verantwortlich !== e.verantwortlich || ex.turnus !== e.turnus; + if (changed) { + report.evidence.updated++; + if (!dryRun) await prisma.policyEvidence.update({ where: { id: ex.id }, data: { policyCode: e.policyCode, nachweis: e.nachweis, quelle: e.quelle, verantwortlich: e.verantwortlich, turnus: e.turnus } }); + } else { + report.evidence.unchanged++; + } + } + report.evidence.obsolete = existingEvidence.filter((e) => !desiredNrs.has(e.nr)).length; + } // Ende reconcileShared (Variablen/Baseline/Nachweise) + + // Änderungsprotokoll ins Audit-Log (nur bei echtem Lauf). + if (!dryRun) { + await prisma.auditLog.create({ + data: { + tenantId, scope: "tenant", actorId: options.actorId ?? null, + action: "import", entity: "policy_package", + after: { framework, ...report } as unknown as object, + }, + }); + } + + return { + documents: pkg.documents.length, + requirements: pkg.requirements.length, + variables: pkg.variables.length, + baseline: pkg.baseline.length, + report, + }; +} + +/** + * Rückwärtskompatibler Datei-Import: parst das Datei-Paket und reconciled es in den + * Mandanten. Wird als Fallback genutzt, solange keine veröffentlichte DB-Vorlage vorliegt. + */ +export async function importPolicies( + prisma: PrismaClient, + tenantId: string, + seedDir: string, + options: ImportOptions = {} +) { + // Datei-Quelle für das Framework des Imports (Default TISAX = mapping.json). + const pkg = parsePackageFiles(seedDir, mappingFileFor(options.framework)); + return reconcilePackage(prisma, tenantId, pkg, options); +} diff --git a/prisma/import-process-catalog.ts b/prisma/import-process-catalog.ts new file mode 100644 index 0000000..6bbeaf8 --- /dev/null +++ b/prisma/import-process-catalog.ts @@ -0,0 +1,256 @@ +// Import des Standard-Prozess-Katalogs (M2 Strukturanalyse, Ebene 2) in das globale +// Modell ProcessCatalogEntry. GLOBALER Content (kein tenantId), analog RiskCatalogEntry. +// Idempotent (Upsert je `code`). Kuratierte Kern-/Management-/Unterstützungsprozesse +// mit Vorschlägen für Träger-Asset-Typen, Standard-Risiken (→ RiskCatalogEntry.code) +// und Info-Labels — angeboten im prozessgeführten Wizard-Schritt. + +import type { AssetType, InfoLabel, PrismaClient, ProcessCategory } from "@prisma/client"; + +interface CatalogSeed { + code: string; + name: string; + category: ProcessCategory; + /** Katalog-Prozess-Tiefe: Code des übergeordneten Katalog-Prozesses (Teilprozess). */ + parentCode?: string; + suggestedAssetTypes: AssetType[]; + suggestedRiskCodes: string[]; + suggestedInfoLabels: InfoLabel[]; +} + +// „Neben"-Prozesse → SUPPORT (Vorgabe). Codes: P-<KAT><nr>, KAT = CORE|MGMT|SUP. +const CATALOG: CatalogSeed[] = [ + // ── Kernprozesse ────────────────────────────────────────────────────────── + { + code: "P-CORE-01", + name: "Auftragsabwicklung", + category: "CORE", + suggestedAssetTypes: ["INFORMATION", "DATA", "APPLICATION", "SYSTEM", "PERSON"], + suggestedRiskCodes: ["R-OPS-01", "R-ORG-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-CORE-02", + name: "Produktentwicklung / Engineering", + category: "CORE", + suggestedAssetTypes: ["INFORMATION", "DATA", "APPLICATION", "PERSON", "SUPPLIER"], + suggestedRiskCodes: ["R-DEV-01", "R-PROTO-01"], + suggestedInfoLabels: ["INFO_VERY_HIGH", "PROTOTYPE"], + }, + { + code: "P-CORE-03", + name: "Produktion / Leistungserbringung", + category: "CORE", + suggestedAssetTypes: ["SYSTEM", "APPLICATION", "LOCATION", "PERSON"], + suggestedRiskCodes: ["R-OPS-01", "R-PHY-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-CORE-04", + name: "Vertrieb & Kundenbetreuung", + category: "CORE", + suggestedAssetTypes: ["INFORMATION", "DATA", "APPLICATION", "PERSON"], + suggestedRiskCodes: ["R-DSGVO-01", "R-HR-01"], + suggestedInfoLabels: ["PERSONAL_DATA"], + }, + // ── Managementprozesse ────────────────────────────────────────────────────── + { + code: "P-MGMT-01", + name: "Unternehmensführung & Strategie", + category: "MANAGEMENT", + suggestedAssetTypes: ["INFORMATION", "PERSON"], + suggestedRiskCodes: ["R-ORG-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-MGMT-02", + name: "Informationssicherheits-Management (ISMS)", + category: "MANAGEMENT", + suggestedAssetTypes: ["INFORMATION", "APPLICATION", "PERSON"], + suggestedRiskCodes: ["R-ORG-01", "R-OPS-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-MGMT-03", + name: "Risiko- & Compliance-Management", + category: "MANAGEMENT", + suggestedAssetTypes: ["INFORMATION", "PERSON"], + suggestedRiskCodes: ["R-ORG-01", "R-DSGVO-01"], + suggestedInfoLabels: ["INFO_HIGH", "PERSONAL_DATA"], + }, + // ── Unterstützende Prozesse (inkl. „Neben"-Prozesse → SUPPORT) ──────────────── + { + code: "P-SUP-01", + name: "IT-Betrieb & Infrastruktur", + category: "SUPPORT", + suggestedAssetTypes: ["SYSTEM", "APPLICATION", "IT_SERVICE", "SOFTWARE", "SUPPLIER", "LOCATION"], + suggestedRiskCodes: ["R-OPS-01", "R-NET-01", "R-IAM-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + // Teilprozesse von P-SUP-01 „IT-Betrieb & Infrastruktur" (parentCode). + { + code: "P-SUP-01-01", + name: "Datensicherung & Wiederherstellung", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["SYSTEM", "IT_SERVICE", "DATA", "SOFTWARE"], + suggestedRiskCodes: ["R-OPS-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-02", + name: "Server-/Virtualisierungsbetrieb", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["SYSTEM", "APPLICATION", "IT_SERVICE"], + suggestedRiskCodes: ["R-OPS-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-03", + name: "Netzwerk-/Firewallbetrieb", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["SYSTEM", "IT_SERVICE"], + suggestedRiskCodes: ["R-NET-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-04", + name: "Patch-/Schwachstellenmanagement", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["SYSTEM", "APPLICATION", "SOFTWARE"], + suggestedRiskCodes: ["R-OPS-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-05", + name: "Monitoring & Alerting", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["SYSTEM", "IT_SERVICE", "APPLICATION"], + suggestedRiskCodes: ["R-OPS-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-06", + name: "Identity-/Access-Betrieb (IAM)", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["APPLICATION", "IT_SERVICE", "PERSON"], + suggestedRiskCodes: ["R-IAM-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-07", + name: "Endpoint-Management", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["SYSTEM", "SOFTWARE", "IT_SERVICE"], + suggestedRiskCodes: ["R-OPS-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-01-08", + name: "RZ-/Cloud-Betrieb", + category: "SUPPORT", + parentCode: "P-SUP-01", + suggestedAssetTypes: ["LOCATION", "IT_SERVICE", "SUPPLIER", "SYSTEM"], + suggestedRiskCodes: ["R-OPS-01", "R-PHY-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-02", + name: "Personalwesen (HR)", + category: "SUPPORT", + suggestedAssetTypes: ["INFORMATION", "DATA", "PERSON", "APPLICATION"], + suggestedRiskCodes: ["R-HR-01", "R-DSGVO-01"], + suggestedInfoLabels: ["PERSONAL_DATA", "INFO_HIGH"], + }, + // Teilprozesse von P-SUP-02 „Personalwesen (HR)" (parentCode). + { + code: "P-SUP-02-01", + name: "Recruiting & Onboarding", + category: "SUPPORT", + parentCode: "P-SUP-02", + suggestedAssetTypes: ["INFORMATION", "DATA", "PERSON", "APPLICATION"], + suggestedRiskCodes: ["R-HR-01", "R-DSGVO-01"], + suggestedInfoLabels: ["PERSONAL_DATA"], + }, + { + code: "P-SUP-02-02", + name: "Offboarding", + category: "SUPPORT", + parentCode: "P-SUP-02", + suggestedAssetTypes: ["INFORMATION", "PERSON", "APPLICATION"], + suggestedRiskCodes: ["R-HR-01", "R-IAM-01"], + suggestedInfoLabels: ["PERSONAL_DATA"], + }, + { + code: "P-SUP-02-03", + name: "Awareness & Schulung", + category: "SUPPORT", + parentCode: "P-SUP-02", + suggestedAssetTypes: ["INFORMATION", "PERSON"], + suggestedRiskCodes: ["R-HR-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-03", + name: "Einkauf & Lieferantensteuerung", + category: "SUPPORT", + suggestedAssetTypes: ["INFORMATION", "SUPPLIER", "IT_SERVICE"], + suggestedRiskCodes: ["R-SUP-01", "R-ORG-01"], + suggestedInfoLabels: ["INFO_HIGH"], + }, + { + code: "P-SUP-04", + name: "Finanzen & Buchhaltung", + category: "SUPPORT", + suggestedAssetTypes: ["INFORMATION", "DATA", "APPLICATION", "PERSON"], + suggestedRiskCodes: ["R-DSGVO-01", "R-ORG-01"], + suggestedInfoLabels: ["INFO_HIGH", "PERSONAL_DATA"], + }, + { + code: "P-SUP-05", + name: "Facility Management & physische Sicherheit", + category: "SUPPORT", + suggestedAssetTypes: ["LOCATION", "SYSTEM", "PERSON"], + suggestedRiskCodes: ["R-PHY-01"], + suggestedInfoLabels: ["NONE"], + }, + // Teilprozesse von P-SUP-05 „Facility Management & physische Sicherheit" (parentCode). + { + code: "P-SUP-05-01", + name: "Zutritts-/Zonenkontrolle", + category: "SUPPORT", + parentCode: "P-SUP-05", + suggestedAssetTypes: ["LOCATION", "SYSTEM", "PERSON"], + suggestedRiskCodes: ["R-PHY-01"], + suggestedInfoLabels: ["NONE"], + }, + { + code: "P-SUP-05-02", + name: "Gebäude-/Versorgungstechnik", + category: "SUPPORT", + parentCode: "P-SUP-05", + suggestedAssetTypes: ["LOCATION", "SYSTEM"], + suggestedRiskCodes: ["R-PHY-01"], + suggestedInfoLabels: ["NONE"], + }, +]; + +/** Schreibt den Katalog (Upsert je code). Liefert die Anzahl. */ +export async function importProcessCatalog(prisma: PrismaClient): Promise<number> { + let orderIdx = 0; + for (const c of CATALOG) { + // parentCode explizit setzen (null bei Hauptprozessen) → idempotente Updates. + const payload = { ...c, parentCode: c.parentCode ?? null, orderIdx: orderIdx++ }; + await prisma.processCatalogEntry.upsert({ + where: { code: c.code }, + update: payload, + create: payload, + }); + } + return CATALOG.length; +} diff --git a/prisma/import-risks.ts b/prisma/import-risks.ts new file mode 100644 index 0000000..0d0b79c --- /dev/null +++ b/prisma/import-risks.ts @@ -0,0 +1,63 @@ +// Import des Standard-Risikokatalogs (Story A6-1) aus dem Fachcontent C4 in das +// globale Modell RiskCatalogEntry. Tabellenzeile: +// +// | R-ORG-01 | Titel | Beschreibung | 1.1.1, 1.2.1 | Richtlinien, Organisation | Standardmaßnahme | E3/S4 — Begründung | +// +// Idempotent (Upsert über code). Kein tenantId (globaler Katalog). + +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import type { PrismaClient } from "@prisma/client"; + +const C4_PATH = join(__dirname, "..", "docs", "wizard-uebergabe", "02_Fachcontent_C1-C9", "C4_Risikokatalog.md"); + +export interface ParsedRisk { + code: string; category: string; title: string; description: string; + controls: string[]; assetTypes: string[]; standardMeasure: string; + defaultLikelihood: number; defaultImpact: number; rationale: string; orderIdx: number; +} + +const splitList = (s: string): string[] => s.split(",").map((x) => x.trim()).filter(Boolean); + +/** Parst die C4-Tabellen zu Katalog-Objekten (ohne DB-Zugriff — testbar). */ +export function parseRiskCatalog(text: string): ParsedRisk[] { + const out: ParsedRisk[] = []; + let i = 0; + for (const line of text.split("\n")) { + const m = line.match(/^\|\s*(R-[A-Z]+-\d+)\s*\|(.*)\|\s*$/); + if (!m) continue; + const cols = m[2].split("|").map((c) => c.trim()); + if (cols.length < 6) continue; // title|desc|controls|assetTypes|measure|ES-rationale + const code = m[1]; + const es = cols[5].match(/E\s*(\d)\s*\/\s*S\s*(\d)/i); + const [, esL, esI] = es ?? []; + out.push({ + code, + category: code.split("-")[1], + title: cols[0], + description: cols[1], + controls: splitList(cols[2]), + assetTypes: splitList(cols[3]), + standardMeasure: cols[4], + defaultLikelihood: esL ? Number(esL) : 3, + defaultImpact: esI ? Number(esI) : 3, + rationale: cols[5].replace(/^E\s*\d\s*\/\s*S\s*\d\s*[—-]\s*/i, "").trim(), + orderIdx: i++, + }); + } + return out; +} + +/** Liest C4 und schreibt den Katalog (Upsert je code). Liefert die Anzahl. */ +export async function importRiskCatalog(prisma: PrismaClient): Promise<number> { + const text = readFileSync(C4_PATH, "utf-8"); + const risks = parseRiskCatalog(text); + for (const r of risks) { + await prisma.riskCatalogEntry.upsert({ + where: { code: r.code }, + update: { category: r.category, title: r.title, description: r.description, controls: r.controls, assetTypes: r.assetTypes, standardMeasure: r.standardMeasure, defaultLikelihood: r.defaultLikelihood, defaultImpact: r.defaultImpact, rationale: r.rationale, orderIdx: r.orderIdx }, + create: r, + }); + } + return risks.length; +} diff --git a/prisma/migrations/20260702095800_init/migration.sql b/prisma/migrations/20260702095800_init/migration.sql new file mode 100644 index 0000000..2e56fd5 --- /dev/null +++ b/prisma/migrations/20260702095800_init/migration.sql @@ -0,0 +1,131 @@ +-- CreateExtension +CREATE EXTENSION IF NOT EXISTS "vector"; + +-- CreateEnum +CREATE TYPE "TenantStatus" AS ENUM ('ACTIVE', 'SUSPENDED'); + +-- CreateEnum +CREATE TYPE "UserStatus" AS ENUM ('ACTIVE', 'INVITED', 'LOCKED', 'DEACTIVATED'); + +-- CreateTable +CREATE TABLE "tenants" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "status" "TenantStatus" NOT NULL DEFAULT 'ACTIVE', + "config" JSONB NOT NULL DEFAULT '{}', + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "tenants_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "users" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password_hash" TEXT NOT NULL, + "name" TEXT NOT NULL, + "status" "UserStatus" NOT NULL DEFAULT 'ACTIVE', + "mfa_secret" TEXT, + "is_platform_admin" BOOLEAN NOT NULL DEFAULT false, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "users_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "roles" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "key" TEXT NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "roles_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "permissions" ( + "id" TEXT NOT NULL, + "key" TEXT NOT NULL, + + CONSTRAINT "permissions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "user_roles" ( + "user_id" TEXT NOT NULL, + "role_id" TEXT NOT NULL, + + CONSTRAINT "user_roles_pkey" PRIMARY KEY ("user_id","role_id") +); + +-- CreateTable +CREATE TABLE "role_permissions" ( + "role_id" TEXT NOT NULL, + "permission_id" TEXT NOT NULL, + + CONSTRAINT "role_permissions_pkey" PRIMARY KEY ("role_id","permission_id") +); + +-- CreateTable +CREATE TABLE "audit_logs" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "actor_id" TEXT, + "action" TEXT NOT NULL, + "entity" TEXT NOT NULL, + "entity_id" TEXT, + "before" JSONB, + "after" JSONB, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "audit_logs_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "tenants_slug_key" ON "tenants"("slug"); + +-- CreateIndex +CREATE INDEX "users_tenant_id_idx" ON "users"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "users_tenant_id_email_key" ON "users"("tenant_id", "email"); + +-- CreateIndex +CREATE INDEX "roles_tenant_id_idx" ON "roles"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "roles_tenant_id_key_key" ON "roles"("tenant_id", "key"); + +-- CreateIndex +CREATE UNIQUE INDEX "permissions_key_key" ON "permissions"("key"); + +-- CreateIndex +CREATE INDEX "audit_logs_tenant_id_entity_entity_id_idx" ON "audit_logs"("tenant_id", "entity", "entity_id"); + +-- CreateIndex +CREATE INDEX "audit_logs_tenant_id_created_at_idx" ON "audit_logs"("tenant_id", "created_at"); + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "roles" ADD CONSTRAINT "roles_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_permission_id_fkey" FOREIGN KEY ("permission_id") REFERENCES "permissions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20260702095816_row_level_security/migration.sql b/prisma/migrations/20260702095816_row_level_security/migration.sql new file mode 100644 index 0000000..4027740 --- /dev/null +++ b/prisma/migrations/20260702095816_row_level_security/migration.sql @@ -0,0 +1,36 @@ +-- Row Level Security als zweite Verteidigungslinie (docs/SPEC.md §2). +-- Primäre Isolation ist der Tenant-Guard in src/server/db.ts. +-- +-- Aktivierungsstand: Policies sind definiert; die App verbindet sich aktuell +-- noch als Tabellen-Owner (Policies greifen für Owner ohne FORCE nicht). +-- Härtungs-Iteration (SPEC §11 Punkt 8): App-Verbindung auf die Rolle +-- "isms_app" umstellen und app.tenant_id pro Transaktion setzen — dann sind +-- die Policies scharf. FORCE wird bewusst nicht gesetzt, damit Migrationen, +-- Seeds und der mandantenübergreifende Login-Lookup als Owner funktionieren. + +-- Eingeschränkte Anwendungsrolle (für die Härtungs-Iteration) +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'isms_app') THEN + CREATE ROLE isms_app NOLOGIN NOBYPASSRLS; + END IF; +END +$$; + +GRANT USAGE ON SCHEMA public TO isms_app; +GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO isms_app; +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO isms_app; + +-- RLS auf allen mandanten-gebundenen Tabellen +ALTER TABLE "users" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "roles" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "audit_logs" ENABLE ROW LEVEL SECURITY; + +-- Isolation: Zugriff nur auf Zeilen des in app.tenant_id gesetzten Mandanten +CREATE POLICY tenant_isolation ON "users" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "roles" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "audit_logs" + USING ("tenant_id" = current_setting('app.tenant_id', true)); diff --git a/prisma/migrations/20260702101647_assets_bia/migration.sql b/prisma/migrations/20260702101647_assets_bia/migration.sql new file mode 100644 index 0000000..62846c8 --- /dev/null +++ b/prisma/migrations/20260702101647_assets_bia/migration.sql @@ -0,0 +1,132 @@ +-- CreateEnum +CREATE TYPE "AssetType" AS ENUM ('INFORMATION', 'SYSTEM', 'APPLICATION', 'LOCATION', 'SUPPLIER', 'PERSON', 'DATA'); + +-- CreateEnum +CREATE TYPE "AssetStatus" AS ENUM ('ACTIVE', 'PLANNED', 'RETIRED'); + +-- CreateEnum +CREATE TYPE "ProcessAssetRole" AS ENUM ('PRIMARY', 'SECONDARY'); + +-- CreateTable +CREATE TABLE "assets" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "type" "AssetType" NOT NULL, + "status" "AssetStatus" NOT NULL DEFAULT 'ACTIVE', + "owner_id" TEXT, + "location" TEXT, + "tags" TEXT[] DEFAULT ARRAY[]::TEXT[], + "confidentiality" INTEGER NOT NULL DEFAULT 1, + "integrity" INTEGER NOT NULL DEFAULT 1, + "availability" INTEGER NOT NULL DEFAULT 1, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "assets_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "asset_relations" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "related_asset_id" TEXT NOT NULL, + "type" TEXT NOT NULL DEFAULT 'depends_on', + + CONSTRAINT "asset_relations_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "processes" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "owner_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "processes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "process_assets" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "process_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "role" "ProcessAssetRole" NOT NULL DEFAULT 'SECONDARY', + + CONSTRAINT "process_assets_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "bia_entries" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "process_id" TEXT NOT NULL, + "rto_hours" INTEGER, + "rpo_hours" INTEGER, + "mtd_hours" INTEGER, + "impact_c" INTEGER NOT NULL DEFAULT 1, + "impact_i" INTEGER NOT NULL DEFAULT 1, + "impact_a" INTEGER NOT NULL DEFAULT 1, + "criticality" INTEGER NOT NULL DEFAULT 1, + "notes" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "bia_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "assets_tenant_id_idx" ON "assets"("tenant_id"); + +-- CreateIndex +CREATE INDEX "assets_tenant_id_type_idx" ON "assets"("tenant_id", "type"); + +-- CreateIndex +CREATE INDEX "asset_relations_tenant_id_idx" ON "asset_relations"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "asset_relations_asset_id_related_asset_id_type_key" ON "asset_relations"("asset_id", "related_asset_id", "type"); + +-- CreateIndex +CREATE INDEX "processes_tenant_id_idx" ON "processes"("tenant_id"); + +-- CreateIndex +CREATE INDEX "process_assets_tenant_id_idx" ON "process_assets"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "process_assets_process_id_asset_id_key" ON "process_assets"("process_id", "asset_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "bia_entries_process_id_key" ON "bia_entries"("process_id"); + +-- CreateIndex +CREATE INDEX "bia_entries_tenant_id_idx" ON "bia_entries"("tenant_id"); + +-- AddForeignKey +ALTER TABLE "assets" ADD CONSTRAINT "assets_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "asset_relations" ADD CONSTRAINT "asset_relations_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "asset_relations" ADD CONSTRAINT "asset_relations_related_asset_id_fkey" FOREIGN KEY ("related_asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "processes" ADD CONSTRAINT "processes_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "process_assets" ADD CONSTRAINT "process_assets_process_id_fkey" FOREIGN KEY ("process_id") REFERENCES "processes"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "process_assets" ADD CONSTRAINT "process_assets_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "bia_entries" ADD CONSTRAINT "bia_entries_process_id_fkey" FOREIGN KEY ("process_id") REFERENCES "processes"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260702101701_rls_assets_bia/migration.sql b/prisma/migrations/20260702101701_rls_assets_bia/migration.sql new file mode 100644 index 0000000..303f54e --- /dev/null +++ b/prisma/migrations/20260702101701_rls_assets_bia/migration.sql @@ -0,0 +1,18 @@ +-- RLS-Policies für die Assets-&-BIA-Tabellen (analog zur Migration row_level_security) + +ALTER TABLE "assets" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "asset_relations" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "processes" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "process_assets" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "bia_entries" ENABLE ROW LEVEL SECURITY; + +CREATE POLICY tenant_isolation ON "assets" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "asset_relations" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "processes" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "process_assets" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "bia_entries" + USING ("tenant_id" = current_setting('app.tenant_id', true)); diff --git a/prisma/migrations/20260702132947_risks_and_process_category/migration.sql b/prisma/migrations/20260702132947_risks_and_process_category/migration.sql new file mode 100644 index 0000000..9ed3855 --- /dev/null +++ b/prisma/migrations/20260702132947_risks_and_process_category/migration.sql @@ -0,0 +1,74 @@ +-- CreateEnum +CREATE TYPE "ProcessCategory" AS ENUM ('CORE', 'MANAGEMENT', 'SUPPORT'); + +-- CreateEnum +CREATE TYPE "RiskTreatment" AS ENUM ('AVOID', 'MITIGATE', 'TRANSFER', 'ACCEPT'); + +-- CreateEnum +CREATE TYPE "RiskStatus" AS ENUM ('OPEN', 'IN_TREATMENT', 'ACCEPTED', 'CLOSED'); + +-- AlterTable +ALTER TABLE "processes" ADD COLUMN "category" "ProcessCategory" NOT NULL DEFAULT 'CORE'; + +-- CreateTable +CREATE TABLE "risks" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "threat" TEXT, + "vulnerability" TEXT, + "likelihood" INTEGER NOT NULL DEFAULT 1, + "impact" INTEGER NOT NULL DEFAULT 1, + "score" INTEGER NOT NULL DEFAULT 1, + "residual_likelihood" INTEGER, + "residual_impact" INTEGER, + "residual_score" INTEGER, + "treatment" "RiskTreatment" NOT NULL DEFAULT 'MITIGATE', + "status" "RiskStatus" NOT NULL DEFAULT 'OPEN', + "owner_id" TEXT, + "process_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "risks_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "risk_assets" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "risk_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + + CONSTRAINT "risk_assets_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "risks_tenant_id_idx" ON "risks"("tenant_id"); + +-- CreateIndex +CREATE INDEX "risks_tenant_id_status_idx" ON "risks"("tenant_id", "status"); + +-- CreateIndex +CREATE UNIQUE INDEX "risks_tenant_id_ref_no_key" ON "risks"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE INDEX "risk_assets_tenant_id_idx" ON "risk_assets"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "risk_assets_risk_id_asset_id_key" ON "risk_assets"("risk_id", "asset_id"); + +-- AddForeignKey +ALTER TABLE "risks" ADD CONSTRAINT "risks_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "risks" ADD CONSTRAINT "risks_process_id_fkey" FOREIGN KEY ("process_id") REFERENCES "processes"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "risk_assets" ADD CONSTRAINT "risk_assets_risk_id_fkey" FOREIGN KEY ("risk_id") REFERENCES "risks"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "risk_assets" ADD CONSTRAINT "risk_assets_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260702133003_rls_risks/migration.sql b/prisma/migrations/20260702133003_rls_risks/migration.sql new file mode 100644 index 0000000..f542644 --- /dev/null +++ b/prisma/migrations/20260702133003_rls_risks/migration.sql @@ -0,0 +1,9 @@ +-- RLS-Policies für die Risiko-Tabellen (analog zu den vorherigen RLS-Migrationen) + +ALTER TABLE "risks" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "risk_assets" ENABLE ROW LEVEL SECURITY; + +CREATE POLICY tenant_isolation ON "risks" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "risk_assets" + USING ("tenant_id" = current_setting('app.tenant_id', true)); diff --git a/prisma/migrations/20260702135246_measures/migration.sql b/prisma/migrations/20260702135246_measures/migration.sql new file mode 100644 index 0000000..d55f998 --- /dev/null +++ b/prisma/migrations/20260702135246_measures/migration.sql @@ -0,0 +1,59 @@ +-- CreateEnum +CREATE TYPE "MeasureStatus" AS ENUM ('OPEN', 'IN_PROGRESS', 'DONE'); + +-- CreateEnum +CREATE TYPE "MeasurePriority" AS ENUM ('LOW', 'MEDIUM', 'HIGH'); + +-- CreateTable +CREATE TABLE "measures" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "status" "MeasureStatus" NOT NULL DEFAULT 'OPEN', + "priority" "MeasurePriority" NOT NULL DEFAULT 'MEDIUM', + "owner_id" TEXT, + "due_date" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "measures_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "risk_measures" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "risk_id" TEXT NOT NULL, + "measure_id" TEXT NOT NULL, + "reduction_likelihood" INTEGER NOT NULL DEFAULT 0, + "reduction_impact" INTEGER NOT NULL DEFAULT 0, + + CONSTRAINT "risk_measures_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "measures_tenant_id_idx" ON "measures"("tenant_id"); + +-- CreateIndex +CREATE INDEX "measures_tenant_id_status_idx" ON "measures"("tenant_id", "status"); + +-- CreateIndex +CREATE UNIQUE INDEX "measures_tenant_id_ref_no_key" ON "measures"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE INDEX "risk_measures_tenant_id_idx" ON "risk_measures"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "risk_measures_risk_id_measure_id_key" ON "risk_measures"("risk_id", "measure_id"); + +-- AddForeignKey +ALTER TABLE "measures" ADD CONSTRAINT "measures_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "risk_measures" ADD CONSTRAINT "risk_measures_risk_id_fkey" FOREIGN KEY ("risk_id") REFERENCES "risks"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "risk_measures" ADD CONSTRAINT "risk_measures_measure_id_fkey" FOREIGN KEY ("measure_id") REFERENCES "measures"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260702135301_rls_measures/migration.sql b/prisma/migrations/20260702135301_rls_measures/migration.sql new file mode 100644 index 0000000..c6708f4 --- /dev/null +++ b/prisma/migrations/20260702135301_rls_measures/migration.sql @@ -0,0 +1,9 @@ +-- RLS-Policies für die Maßnahmen-Tabellen + +ALTER TABLE "measures" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "risk_measures" ENABLE ROW LEVEL SECURITY; + +CREATE POLICY tenant_isolation ON "measures" + USING ("tenant_id" = current_setting('app.tenant_id', true)); +CREATE POLICY tenant_isolation ON "risk_measures" + USING ("tenant_id" = current_setting('app.tenant_id', true)); diff --git a/prisma/migrations/20260702144829_decimal_reductions_and_catalogs/migration.sql b/prisma/migrations/20260702144829_decimal_reductions_and_catalogs/migration.sql new file mode 100644 index 0000000..0480c08 --- /dev/null +++ b/prisma/migrations/20260702144829_decimal_reductions_and_catalogs/migration.sql @@ -0,0 +1,32 @@ +-- AlterTable +ALTER TABLE "risk_measures" ALTER COLUMN "reduction_likelihood" SET DEFAULT 0, +ALTER COLUMN "reduction_likelihood" SET DATA TYPE DOUBLE PRECISION, +ALTER COLUMN "reduction_impact" SET DEFAULT 0, +ALTER COLUMN "reduction_impact" SET DATA TYPE DOUBLE PRECISION; + +-- AlterTable +ALTER TABLE "risks" ALTER COLUMN "residual_likelihood" SET DATA TYPE DOUBLE PRECISION, +ALTER COLUMN "residual_impact" SET DATA TYPE DOUBLE PRECISION, +ALTER COLUMN "residual_score" SET DATA TYPE DOUBLE PRECISION; + +-- CreateTable +CREATE TABLE "threats" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "threats_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "vulnerabilities" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "vulnerabilities_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "threats_name_key" ON "threats"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "vulnerabilities_name_key" ON "vulnerabilities"("name"); diff --git a/prisma/migrations/20260703081059_suppliers/migration.sql b/prisma/migrations/20260703081059_suppliers/migration.sql new file mode 100644 index 0000000..1cc6df3 --- /dev/null +++ b/prisma/migrations/20260703081059_suppliers/migration.sql @@ -0,0 +1,260 @@ +-- CreateEnum +CREATE TYPE "SupplierStatus" AS ENUM ('ACTIVE', 'ONBOARDING', 'UNDER_REVIEW', 'OFFBOARDED'); + +-- CreateEnum +CREATE TYPE "AssessmentType" AS ENUM ('QUESTIONNAIRE', 'SELF_ASSESSMENT', 'AUDIT'); + +-- CreateEnum +CREATE TYPE "AssessmentStatus" AS ENUM ('SENT', 'RECEIVED', 'EVALUATED', 'OVERDUE'); + +-- CreateEnum +CREATE TYPE "EvidenceKind" AS ENUM ('CERTIFICATE', 'TISAX_LABEL', 'ATTESTATION', 'AUDIT_REPORT', 'SELF_ASSESSMENT'); + +-- CreateEnum +CREATE TYPE "ResponsibleParty" AS ENUM ('CLIENT', 'SUPPLIER', 'SHARED'); + +-- CreateTable +CREATE TABLE "suppliers" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "name" TEXT NOT NULL, + "sector" TEXT, + "services" TEXT, + "criticality" INTEGER NOT NULL DEFAULT 1, + "data_categories" TEXT[] DEFAULT ARRAY[]::TEXT[], + "confidentiality" INTEGER NOT NULL DEFAULT 1, + "integrity" INTEGER NOT NULL DEFAULT 1, + "availability" INTEGER NOT NULL DEFAULT 1, + "nis2_relevant" BOOLEAN NOT NULL DEFAULT false, + "status" "SupplierStatus" NOT NULL DEFAULT 'ACTIVE', + "contact" TEXT, + "next_review" TIMESTAMP(3), + "notes" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "suppliers_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "supplier_assets" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + + CONSTRAINT "supplier_assets_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "supplier_assessments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "type" "AssessmentType" NOT NULL, + "status" "AssessmentStatus" NOT NULL DEFAULT 'SENT', + "score" INTEGER, + "date" TIMESTAMP(3), + "next_review" TIMESTAMP(3), + "result" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "supplier_assessments_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "contracts" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "type" TEXT NOT NULL DEFAULT 'service', + "av_dpa" BOOLEAN NOT NULL DEFAULT false, + "security_clauses" BOOLEAN NOT NULL DEFAULT false, + "flowdown" BOOLEAN NOT NULL DEFAULT false, + "customer_transparency" BOOLEAN NOT NULL DEFAULT false, + "valid_from" TIMESTAMP(3), + "valid_to" TIMESTAMP(3), + "reference" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "contracts_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ndas" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "parties" TEXT, + "info_scope" TEXT, + "subject" TEXT, + "valid_from" TIMESTAMP(3), + "valid_to" TIMESTAMP(3), + "obligations" TEXT, + "extension_status" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "ndas_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "supplier_evidence" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "kind" "EvidenceKind" NOT NULL, + "name" TEXT, + "protects_cia" TEXT, + "valid_to" TIMESTAMP(3), + "adequacy_checked" BOOLEAN NOT NULL DEFAULT false, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "supplier_evidence_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "service_responsibilities" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "it_service" TEXT NOT NULL, + "requirement" TEXT NOT NULL, + "responsible_party" "ResponsibleParty" NOT NULL DEFAULT 'SHARED', + "isa_applicability" TEXT, + "evidence" TEXT, + "integrated_local_controls" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "service_responsibilities_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "subcontractors" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "flowdown_obligation" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "subcontractors_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "management_decisions" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "reason_no_audit" TEXT NOT NULL, + "decision" TEXT NOT NULL, + "decided_by" TEXT, + "date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "record_ref" TEXT, + + CONSTRAINT "management_decisions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "supplier_controls" ( + "id" TEXT NOT NULL, + "ref" TEXT NOT NULL, + "title" TEXT NOT NULL, + "objective" TEXT NOT NULL, + "must_req" TEXT, + "should_req" TEXT, + "high_req" TEXT, + "very_high_req" TEXT, + "simplified_group_assessment" BOOLEAN NOT NULL DEFAULT false, + "target_maturity" INTEGER NOT NULL DEFAULT 3, + "references" TEXT, + + CONSTRAINT "supplier_controls_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "supplier_control_maturity" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "supplier_id" TEXT NOT NULL, + "control_id" TEXT NOT NULL, + "maturity" INTEGER NOT NULL DEFAULT 0, + "notes" TEXT, + + CONSTRAINT "supplier_control_maturity_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "suppliers_tenant_id_idx" ON "suppliers"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "suppliers_tenant_id_ref_no_key" ON "suppliers"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE INDEX "supplier_assets_tenant_id_idx" ON "supplier_assets"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "supplier_assets_supplier_id_asset_id_key" ON "supplier_assets"("supplier_id", "asset_id"); + +-- CreateIndex +CREATE INDEX "supplier_assessments_tenant_id_idx" ON "supplier_assessments"("tenant_id"); + +-- CreateIndex +CREATE INDEX "contracts_tenant_id_idx" ON "contracts"("tenant_id"); + +-- CreateIndex +CREATE INDEX "ndas_tenant_id_idx" ON "ndas"("tenant_id"); + +-- CreateIndex +CREATE INDEX "supplier_evidence_tenant_id_idx" ON "supplier_evidence"("tenant_id"); + +-- CreateIndex +CREATE INDEX "service_responsibilities_tenant_id_idx" ON "service_responsibilities"("tenant_id"); + +-- CreateIndex +CREATE INDEX "subcontractors_tenant_id_idx" ON "subcontractors"("tenant_id"); + +-- CreateIndex +CREATE INDEX "management_decisions_tenant_id_idx" ON "management_decisions"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "supplier_controls_ref_key" ON "supplier_controls"("ref"); + +-- CreateIndex +CREATE INDEX "supplier_control_maturity_tenant_id_idx" ON "supplier_control_maturity"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "supplier_control_maturity_supplier_id_control_id_key" ON "supplier_control_maturity"("supplier_id", "control_id"); + +-- AddForeignKey +ALTER TABLE "supplier_assets" ADD CONSTRAINT "supplier_assets_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_assets" ADD CONSTRAINT "supplier_assets_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_assessments" ADD CONSTRAINT "supplier_assessments_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "contracts" ADD CONSTRAINT "contracts_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ndas" ADD CONSTRAINT "ndas_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_evidence" ADD CONSTRAINT "supplier_evidence_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "service_responsibilities" ADD CONSTRAINT "service_responsibilities_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "subcontractors" ADD CONSTRAINT "subcontractors_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "management_decisions" ADD CONSTRAINT "management_decisions_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_control_maturity" ADD CONSTRAINT "supplier_control_maturity_supplier_id_fkey" FOREIGN KEY ("supplier_id") REFERENCES "suppliers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_control_maturity" ADD CONSTRAINT "supplier_control_maturity_control_id_fkey" FOREIGN KEY ("control_id") REFERENCES "supplier_controls"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260703081120_rls_suppliers/migration.sql b/prisma/migrations/20260703081120_rls_suppliers/migration.sql new file mode 100644 index 0000000..8bef651 --- /dev/null +++ b/prisma/migrations/20260703081120_rls_suppliers/migration.sql @@ -0,0 +1,16 @@ +-- RLS-Policies für die Lieferanten-Tabellen (analog zu row_level_security) +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY[ + 'suppliers','supplier_assets','supplier_assessments','contracts','ndas', + 'supplier_evidence','service_responsibilities','subcontractors', + 'management_decisions','supplier_control_maturity' + ] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format( + 'CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', + t + ); + END LOOP; +END $$; diff --git a/prisma/migrations/20260703113715_suppliers_as_assets/migration.sql b/prisma/migrations/20260703113715_suppliers_as_assets/migration.sql new file mode 100644 index 0000000..106a816 --- /dev/null +++ b/prisma/migrations/20260703113715_suppliers_as_assets/migration.sql @@ -0,0 +1,239 @@ +-- CreateEnum +CREATE TYPE "SupplierLifecycle" AS ENUM ('ACTIVE', 'ONBOARDING', 'UNDER_REVIEW', 'OFFBOARDED'); + +-- CreateEnum +CREATE TYPE "RaciResponsibility" AS ENUM ('PROVIDER', 'US', 'SHARED'); + +-- AlterEnum +ALTER TYPE "AssetType" ADD VALUE 'IT_SERVICE'; + +-- DropForeignKey +ALTER TABLE "contracts" DROP CONSTRAINT "contracts_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "management_decisions" DROP CONSTRAINT "management_decisions_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "ndas" DROP CONSTRAINT "ndas_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "service_responsibilities" DROP CONSTRAINT "service_responsibilities_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "subcontractors" DROP CONSTRAINT "subcontractors_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "supplier_assessments" DROP CONSTRAINT "supplier_assessments_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "supplier_assets" DROP CONSTRAINT "supplier_assets_asset_id_fkey"; + +-- DropForeignKey +ALTER TABLE "supplier_assets" DROP CONSTRAINT "supplier_assets_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "supplier_control_maturity" DROP CONSTRAINT "supplier_control_maturity_control_id_fkey"; + +-- DropForeignKey +ALTER TABLE "supplier_control_maturity" DROP CONSTRAINT "supplier_control_maturity_supplier_id_fkey"; + +-- DropForeignKey +ALTER TABLE "supplier_evidence" DROP CONSTRAINT "supplier_evidence_supplier_id_fkey"; + +-- AlterTable +ALTER TABLE "contracts" DROP COLUMN "customer_transparency", +DROP COLUMN "supplier_id", +ADD COLUMN "asset_id" TEXT NOT NULL, +ADD COLUMN "customer_requirements_passed" BOOLEAN NOT NULL DEFAULT false; + +-- AlterTable +ALTER TABLE "management_decisions" DROP COLUMN "supplier_id", +ADD COLUMN "asset_id" TEXT NOT NULL; + +-- AlterTable +ALTER TABLE "ndas" DROP COLUMN "supplier_id", +ADD COLUMN "asset_id" TEXT NOT NULL, +ADD COLUMN "beyond_term" BOOLEAN NOT NULL DEFAULT false; + +-- AlterTable +ALTER TABLE "subcontractors" DROP COLUMN "supplier_id", +ADD COLUMN "asset_id" TEXT NOT NULL; + +-- AlterTable +ALTER TABLE "supplier_assessments" DROP COLUMN "status", +DROP COLUMN "supplier_id", +ADD COLUMN "asset_id" TEXT NOT NULL, +ADD COLUMN "self_score" INTEGER, +ADD COLUMN "verified_score" INTEGER; + +-- AlterTable +ALTER TABLE "supplier_evidence" DROP COLUMN "supplier_id", +ADD COLUMN "asset_id" TEXT NOT NULL; + +-- DropTable +DROP TABLE "service_responsibilities"; + +-- DropTable +DROP TABLE "supplier_assets"; + +-- DropTable +DROP TABLE "supplier_control_maturity"; + +-- DropTable +DROP TABLE "supplier_controls"; + +-- DropTable +DROP TABLE "suppliers"; + +-- DropEnum +DROP TYPE "AssessmentStatus"; + +-- DropEnum +DROP TYPE "ResponsibleParty"; + +-- DropEnum +DROP TYPE "SupplierStatus"; + +-- CreateTable +CREATE TABLE "supplier_profiles" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "sector" TEXT, + "service_desc" TEXT, + "criticality" INTEGER NOT NULL DEFAULT 1, + "data_categories" TEXT[] DEFAULT ARRAY[]::TEXT[], + "nis2_relevant" BOOLEAN NOT NULL DEFAULT false, + "lifecycle" "SupplierLifecycle" NOT NULL DEFAULT 'ACTIVE', + "contact" TEXT, + "tisax_label" TEXT, + "tisax_valid_to" TIMESTAMP(3), + "next_review" TIMESTAMP(3), + "notes" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "supplier_profiles_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "it_service_profiles" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "provider_asset_id" TEXT, + "criticality" INTEGER NOT NULL DEFAULT 1, + "internal" BOOLEAN NOT NULL DEFAULT false, + "notes" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "it_service_profiles_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "service_control_responsibilities" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "control_ref" TEXT NOT NULL, + "title" TEXT, + "applicable" BOOLEAN NOT NULL DEFAULT true, + "responsibility" "RaciResponsibility" NOT NULL DEFAULT 'SHARED', + "evidence_ref" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "service_control_responsibilities_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "maturity_assessments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "self_value" DOUBLE PRECISION, + "verified_value" DOUBLE PRECISION, + "computed_value" DOUBLE PRECISION, + "isb_value" DOUBLE PRECISION, + "isb_justification" TEXT, + "approved_by" TEXT, + "approved_at" TIMESTAMP(3), + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "maturity_assessments_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "supplier_profiles_asset_id_key" ON "supplier_profiles"("asset_id"); + +-- CreateIndex +CREATE INDEX "supplier_profiles_tenant_id_idx" ON "supplier_profiles"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "supplier_profiles_tenant_id_ref_no_key" ON "supplier_profiles"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE UNIQUE INDEX "it_service_profiles_asset_id_key" ON "it_service_profiles"("asset_id"); + +-- CreateIndex +CREATE INDEX "it_service_profiles_tenant_id_idx" ON "it_service_profiles"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "it_service_profiles_tenant_id_ref_no_key" ON "it_service_profiles"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE INDEX "service_control_responsibilities_tenant_id_idx" ON "service_control_responsibilities"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "maturity_assessments_asset_id_key" ON "maturity_assessments"("asset_id"); + +-- CreateIndex +CREATE INDEX "maturity_assessments_tenant_id_idx" ON "maturity_assessments"("tenant_id"); + +-- AddForeignKey +ALTER TABLE "supplier_profiles" ADD CONSTRAINT "supplier_profiles_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "it_service_profiles" ADD CONSTRAINT "it_service_profiles_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "it_service_profiles" ADD CONSTRAINT "it_service_profiles_provider_asset_id_fkey" FOREIGN KEY ("provider_asset_id") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_assessments" ADD CONSTRAINT "supplier_assessments_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "supplier_evidence" ADD CONSTRAINT "supplier_evidence_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "management_decisions" ADD CONSTRAINT "management_decisions_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "contracts" ADD CONSTRAINT "contracts_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ndas" ADD CONSTRAINT "ndas_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "subcontractors" ADD CONSTRAINT "subcontractors_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "service_control_responsibilities" ADD CONSTRAINT "service_control_responsibilities_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "maturity_assessments" ADD CONSTRAINT "maturity_assessments_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- RLS für neue/umgestellte Lieferanten-Tabellen +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['supplier_profiles','it_service_profiles','maturity_assessments','service_control_responsibilities'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260707132008_policies/migration.sql b/prisma/migrations/20260707132008_policies/migration.sql new file mode 100644 index 0000000..0175d0a --- /dev/null +++ b/prisma/migrations/20260707132008_policies/migration.sql @@ -0,0 +1,136 @@ +-- CreateEnum +CREATE TYPE "PolicyDocType" AS ENUM ('LEITLINIE', 'RICHTLINIE', 'VERFAHREN', 'REGISTER', 'HANDBUCH', 'EIGENES'); + +-- CreateEnum +CREATE TYPE "PolicyStatus" AS ENUM ('ENTWURF', 'IN_FREIGABE', 'FREIGEGEBEN', 'ARCHIVIERT'); + +-- CreateTable +CREATE TABLE "policy_documents" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "type" "PolicyDocType" NOT NULL, + "title" TEXT NOT NULL, + "version" TEXT NOT NULL DEFAULT '1.0', + "status" "PolicyStatus" NOT NULL DEFAULT 'FREIGEGEBEN', + "owner" TEXT, + "policy_code" TEXT, + "fulfills" TEXT[] DEFAULT ARRAY[]::TEXT[], + "raw_markdown" TEXT NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "policy_documents_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_requirements" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "req_id" TEXT NOT NULL, + "policy_code" TEXT NOT NULL, + "control" TEXT NOT NULL, + "obligation" TEXT NOT NULL, + "condition" TEXT, + "requirement" TEXT NOT NULL, + "implementation" TEXT NOT NULL, + "va_codes" TEXT[] DEFAULT ARRAY[]::TEXT[], + "nachweis_link" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_requirements_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_variables" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "key" TEXT NOT NULL, + "title" TEXT NOT NULL, + "kind" TEXT NOT NULL, + "group_name" TEXT, + "value" TEXT NOT NULL, + "required" BOOLEAN NOT NULL DEFAULT false, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "policy_variables_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_baseline_params" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "bl_id" TEXT NOT NULL, + "section" TEXT NOT NULL, + "name" TEXT NOT NULL, + "vorgabe" TEXT NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_baseline_params_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_evidence" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "nr" INTEGER NOT NULL, + "policy_code" TEXT NOT NULL, + "nachweis" TEXT NOT NULL, + "quelle" TEXT NOT NULL, + "verantwortlich" TEXT NOT NULL, + "turnus" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_evidence_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "policy_documents_tenant_id_idx" ON "policy_documents"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_documents_tenant_id_code_key" ON "policy_documents"("tenant_id", "code"); + +-- CreateIndex +CREATE INDEX "policy_requirements_tenant_id_idx" ON "policy_requirements"("tenant_id"); + +-- CreateIndex +CREATE INDEX "policy_requirements_tenant_id_control_idx" ON "policy_requirements"("tenant_id", "control"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_requirements_tenant_id_req_id_key" ON "policy_requirements"("tenant_id", "req_id"); + +-- CreateIndex +CREATE INDEX "policy_variables_tenant_id_idx" ON "policy_variables"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_variables_tenant_id_key_key" ON "policy_variables"("tenant_id", "key"); + +-- CreateIndex +CREATE INDEX "policy_baseline_params_tenant_id_idx" ON "policy_baseline_params"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_baseline_params_tenant_id_bl_id_key" ON "policy_baseline_params"("tenant_id", "bl_id"); + +-- CreateIndex +CREATE INDEX "policy_evidence_tenant_id_idx" ON "policy_evidence"("tenant_id"); + + +-- RLS-Policies für die Richtlinien-Tabellen +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY[ + 'policy_documents','policy_requirements','policy_variables', + 'policy_baseline_params','policy_evidence' + ] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format( + 'CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', + t + ); + END LOOP; +END $$; diff --git a/prisma/migrations/20260707153909_managed_tables/migration.sql b/prisma/migrations/20260707153909_managed_tables/migration.sql new file mode 100644 index 0000000..ec3afb1 --- /dev/null +++ b/prisma/migrations/20260707153909_managed_tables/migration.sql @@ -0,0 +1,156 @@ +-- CreateTable +CREATE TABLE "crypto_entries" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "dienst" TEXT NOT NULL, + "schluessel" TEXT NOT NULL, + "algorithmus" TEXT, + "ablauf_datum" TIMESTAMP(3), + "verantwortlich" TEXT NOT NULL, + "speicherort" TEXT, + "baseline_ref" TEXT, + "notes" TEXT, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "crypto_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "classification_classes" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "classification_classes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "handling_aspects" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "category" TEXT, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "handling_aspects_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "handling_rules" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "class_id" TEXT NOT NULL, + "aspect_id" TEXT NOT NULL, + "text" TEXT NOT NULL, + + CONSTRAINT "handling_rules_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "risk_matrix_classes" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "max_score" INTEGER NOT NULL, + "acceptance" TEXT NOT NULL, + "tone" TEXT NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "risk_matrix_classes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "risk_ew_levels" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "level" INTEGER NOT NULL, + "label" TEXT NOT NULL, + "definition" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "risk_ew_levels_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "risk_damage_dimensions" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "levels" JSONB NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "risk_damage_dimensions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "handbook_topics" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "category" TEXT NOT NULL, + "title" TEXT NOT NULL, + "body_md" TEXT NOT NULL, + "source_refs" TEXT[] DEFAULT ARRAY[]::TEXT[], + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "handbook_topics_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "crypto_entries_tenant_id_idx" ON "crypto_entries"("tenant_id"); + +-- CreateIndex +CREATE INDEX "classification_classes_tenant_id_idx" ON "classification_classes"("tenant_id"); + +-- CreateIndex +CREATE INDEX "handling_aspects_tenant_id_idx" ON "handling_aspects"("tenant_id"); + +-- CreateIndex +CREATE INDEX "handling_rules_tenant_id_idx" ON "handling_rules"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "handling_rules_class_id_aspect_id_key" ON "handling_rules"("class_id", "aspect_id"); + +-- CreateIndex +CREATE INDEX "risk_matrix_classes_tenant_id_idx" ON "risk_matrix_classes"("tenant_id"); + +-- CreateIndex +CREATE INDEX "risk_ew_levels_tenant_id_idx" ON "risk_ew_levels"("tenant_id"); + +-- CreateIndex +CREATE INDEX "risk_damage_dimensions_tenant_id_idx" ON "risk_damage_dimensions"("tenant_id"); + +-- CreateIndex +CREATE INDEX "handbook_topics_tenant_id_idx" ON "handbook_topics"("tenant_id"); + +-- AddForeignKey +ALTER TABLE "handling_rules" ADD CONSTRAINT "handling_rules_class_id_fkey" FOREIGN KEY ("class_id") REFERENCES "classification_classes"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "handling_rules" ADD CONSTRAINT "handling_rules_aspect_id_fkey" FOREIGN KEY ("aspect_id") REFERENCES "handling_aspects"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- RLS-Policies für die verwalteten Register-Tabellen +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY[ + 'crypto_entries','classification_classes','handling_aspects','handling_rules', + 'risk_matrix_classes','risk_ew_levels','risk_damage_dimensions','handbook_topics' + ] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format( + 'CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', + t + ); + END LOOP; +END $$; diff --git a/prisma/migrations/20260707163523_policy_approval/migration.sql b/prisma/migrations/20260707163523_policy_approval/migration.sql new file mode 100644 index 0000000..8e8145e --- /dev/null +++ b/prisma/migrations/20260707163523_policy_approval/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "policy_documents" ADD COLUMN "approved_at" TIMESTAMP(3), +ADD COLUMN "approved_by" TEXT, +ADD COLUMN "submitted_by" TEXT; + diff --git a/prisma/migrations/20260708111123_policy_protection_override/migration.sql b/prisma/migrations/20260708111123_policy_protection_override/migration.sql new file mode 100644 index 0000000..6f3d910 --- /dev/null +++ b/prisma/migrations/20260708111123_policy_protection_override/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "policy_documents" ADD COLUMN "protection_override" TEXT; + diff --git a/prisma/migrations/20260719203024_admin_console/migration.sql b/prisma/migrations/20260719203024_admin_console/migration.sql new file mode 100644 index 0000000..03f0049 --- /dev/null +++ b/prisma/migrations/20260719203024_admin_console/migration.sql @@ -0,0 +1,78 @@ +-- AlterEnum +ALTER TYPE "TenantStatus" ADD VALUE 'ARCHIVED'; + +-- AlterTable +ALTER TABLE "audit_logs" ADD COLUMN "scope" TEXT NOT NULL DEFAULT 'tenant'; + +-- AlterTable +ALTER TABLE "tenants" ADD COLUMN "sector" TEXT, +ADD COLUMN "short" TEXT; + +-- CreateTable +CREATE TABLE "tenant_settings" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "org_name" TEXT NOT NULL, + "org_short" TEXT, + "address" TEXT, + "sector" TEXT, + "duns" TEXT, + "isms_scope" TEXT, + "isms_scope_description" TEXT, + "role_management" TEXT, + "role_isb" TEXT, + "role_it_lead" TEXT, + "role_dpo" TEXT, + "logo_key" TEXT, + "accent" TEXT, + "locale" TEXT NOT NULL DEFAULT 'de', + "timezone" TEXT NOT NULL DEFAULT 'Europe/Berlin', + "tisax_level" TEXT NOT NULL DEFAULT 'AL2', + "security_policy" JSONB NOT NULL DEFAULT '{}', + "smtp" JSONB NOT NULL DEFAULT '{}', + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "tenant_settings_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "tenant_modules" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "module_key" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "tenant_modules_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "tenant_settings_tenant_id_key" ON "tenant_settings"("tenant_id"); + +-- CreateIndex +CREATE INDEX "tenant_settings_tenant_id_idx" ON "tenant_settings"("tenant_id"); + +-- CreateIndex +CREATE INDEX "tenant_modules_tenant_id_idx" ON "tenant_modules"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "tenant_modules_tenant_id_module_key_key" ON "tenant_modules"("tenant_id", "module_key"); + +-- AddForeignKey +ALTER TABLE "tenant_settings" ADD CONSTRAINT "tenant_settings_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "tenant_modules" ADD CONSTRAINT "tenant_modules_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- RLS für die neuen mandantenbezogenen Tabellen +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['tenant_settings','tenant_modules'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260720183635_platform_admins/migration.sql b/prisma/migrations/20260720183635_platform_admins/migration.sql new file mode 100644 index 0000000..e92c157 --- /dev/null +++ b/prisma/migrations/20260720183635_platform_admins/migration.sql @@ -0,0 +1,46 @@ +-- DropForeignKey +ALTER TABLE "audit_logs" DROP CONSTRAINT "audit_logs_tenant_id_fkey"; + +-- AlterTable +ALTER TABLE "audit_logs" ALTER COLUMN "tenant_id" DROP NOT NULL; + +-- CreateTable +CREATE TABLE "platform_admins" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password_hash" TEXT NOT NULL, + "name" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'ACTIVE', + "mfa_secret" TEXT, + "mfa_enrolled_at" TIMESTAMP(3), + "recovery_codes" JSONB NOT NULL DEFAULT '[]', + "failed_logins" INTEGER NOT NULL DEFAULT 0, + "locked_until" TIMESTAMP(3), + "last_login_at" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "platform_admins_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "platform_admins_email_key" ON "platform_admins"("email"); + +-- AddForeignKey +ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE SET NULL ON UPDATE CASCADE; + + +-- Datenmigration (Phase-1-Härtung Paket 2): bestehende isPlatformAdmin-Nutzer in den +-- getrennten PlatformAdmin-Store übernehmen (gleicher Argon2-Hash → Login sofort möglich) +-- und das Mandanten-Flag zurücksetzen. MFA wird beim ersten Plattform-Login eingerichtet. +INSERT INTO "platform_admins" ("id", "email", "password_hash", "name", "status", "recovery_codes", "failed_logins", "created_at", "updated_at") +SELECT gen_random_uuid()::text, lower("email"), "password_hash", "name", 'ACTIVE', '[]'::jsonb, 0, now(), now() +FROM "users" +WHERE "is_platform_admin" = true +ON CONFLICT ("email") DO NOTHING; + +UPDATE "users" SET "is_platform_admin" = false WHERE "is_platform_admin" = true; + +-- platform_admins ist plattformweit (kein tenant_id) → RLS bewusst NICHT aktiviert. +-- Zugriff für die eingeschränkte App-Rolle (Härtungs-Iteration) explizit gewähren. +GRANT SELECT, INSERT, UPDATE, DELETE ON "platform_admins" TO isms_app; diff --git a/prisma/migrations/20260721113710_policy_lifecycle_archived/migration.sql b/prisma/migrations/20260721113710_policy_lifecycle_archived/migration.sql new file mode 100644 index 0000000..0e691a8 --- /dev/null +++ b/prisma/migrations/20260721113710_policy_lifecycle_archived/migration.sql @@ -0,0 +1,6 @@ +-- AlterTable +ALTER TABLE "policy_documents" ADD COLUMN "archived_at" TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "policy_requirements" ADD COLUMN "archived_at" TIMESTAMP(3); + diff --git a/prisma/migrations/20260722071432_user_mgmt_and_platform_settings/migration.sql b/prisma/migrations/20260722071432_user_mgmt_and_platform_settings/migration.sql new file mode 100644 index 0000000..cc20255 --- /dev/null +++ b/prisma/migrations/20260722071432_user_mgmt_and_platform_settings/migration.sql @@ -0,0 +1,22 @@ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "mfa_enrolled_at" TIMESTAMP(3), +ADD COLUMN "must_change_password" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "recovery_codes" JSONB NOT NULL DEFAULT '[]'; + +-- CreateTable +CREATE TABLE "platform_settings" ( + "id" TEXT NOT NULL DEFAULT 'singleton', + "mfa_required" BOOLEAN NOT NULL DEFAULT false, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "platform_settings_pkey" PRIMARY KEY ("id") +); + + +-- platform_settings ist plattformweit (kein tenant_id) → RLS nicht aktiviert. +GRANT SELECT, INSERT, UPDATE, DELETE ON "platform_settings" TO isms_app; + +-- Singleton-Zeile anlegen (MFA-Pflicht standardmäßig aus). +INSERT INTO "platform_settings" ("id", "mfa_required", "updated_at") +VALUES ('singleton', false, now()) +ON CONFLICT ("id") DO NOTHING; diff --git a/prisma/migrations/20260722092625_tasks/migration.sql b/prisma/migrations/20260722092625_tasks/migration.sql new file mode 100644 index 0000000..0fca78d --- /dev/null +++ b/prisma/migrations/20260722092625_tasks/migration.sql @@ -0,0 +1,56 @@ +-- CreateTable +CREATE TABLE "tasks" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "type" TEXT NOT NULL, + "title" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'OPEN', + "entity_type" TEXT, + "entity_id" TEXT, + "entity_ref" TEXT, + "assignee_id" TEXT, + "created_by_id" TEXT, + "due_date" TIMESTAMP(3), + "resolved_by_id" TEXT, + "resolved_at" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "tasks_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "task_comments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "task_id" TEXT NOT NULL, + "author_id" TEXT, + "kind" TEXT NOT NULL DEFAULT 'comment', + "body" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "task_comments_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "tasks_tenant_id_status_idx" ON "tasks"("tenant_id", "status"); + +-- CreateIndex +CREATE INDEX "tasks_tenant_id_assignee_id_status_idx" ON "tasks"("tenant_id", "assignee_id", "status"); + +-- CreateIndex +CREATE INDEX "task_comments_tenant_id_task_id_idx" ON "task_comments"("tenant_id", "task_id"); + +-- AddForeignKey +ALTER TABLE "task_comments" ADD CONSTRAINT "task_comments_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- RLS für die neuen mandantenbezogenen Tabellen (zweite Verteidigungslinie). +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['tasks','task_comments'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260723071617_strip_tool_variable_articles/migration.sql b/prisma/migrations/20260723071617_strip_tool_variable_articles/migration.sql new file mode 100644 index 0000000..7ec14a6 --- /dev/null +++ b/prisma/migrations/20260723071617_strip_tool_variable_articles/migration.sql @@ -0,0 +1,9 @@ +-- WP2.2 (Rendering Variante B): führenden Artikel aus den betroffenen Variablen-Werten +-- entfernen, damit "im {{VAR}}" nicht mehr zu "im das …" rendert. Nur nicht angepasste +-- Werte (= alter Default) werden migriert; kundenindividuelle Werte bleiben unberührt. +UPDATE "policy_variables" SET "value" = 'Ticketsystem' + WHERE "key" = 'TOOL_TICKET' AND "value" = 'das Ticketsystem'; +UPDATE "policy_variables" SET "value" = 'ISMS-Tool' + WHERE "key" = 'TOOL_NAME' AND "value" = 'das ISMS-Tool'; +UPDATE "policy_variables" SET "value" = 'Entra ID / Active Directory' + WHERE "key" = 'TOOL_IAM' AND "value" = 'das zentrale Verzeichnis (Entra ID / Active Directory)'; diff --git a/prisma/migrations/20260723090004_managed_registers/migration.sql b/prisma/migrations/20260723090004_managed_registers/migration.sql new file mode 100644 index 0000000..83e6078 --- /dev/null +++ b/prisma/migrations/20260723090004_managed_registers/migration.sql @@ -0,0 +1,55 @@ +-- CreateTable +CREATE TABLE "managed_registers" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "columns" JSONB NOT NULL DEFAULT '[]', + "review_cycle" TEXT, + "responsible" TEXT, + "supplier_link" BOOLEAN NOT NULL DEFAULT false, + "asset_link" BOOLEAN NOT NULL DEFAULT false, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "managed_registers_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "register_rows" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "register_id" TEXT NOT NULL, + "values" JSONB NOT NULL DEFAULT '{}', + "supplier_ref" TEXT, + "asset_ref" TEXT, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "register_rows_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "managed_registers_tenant_id_idx" ON "managed_registers"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "managed_registers_tenant_id_code_key" ON "managed_registers"("tenant_id", "code"); + +-- CreateIndex +CREATE INDEX "register_rows_tenant_id_register_id_idx" ON "register_rows"("tenant_id", "register_id"); + +-- AddForeignKey +ALTER TABLE "register_rows" ADD CONSTRAINT "register_rows_register_id_fkey" FOREIGN KEY ("register_id") REFERENCES "managed_registers"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- RLS für die neuen mandantenbezogenen Tabellen. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['managed_registers','register_rows'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260724095408_software_and_project_assets/migration.sql b/prisma/migrations/20260724095408_software_and_project_assets/migration.sql new file mode 100644 index 0000000..93b2885 --- /dev/null +++ b/prisma/migrations/20260724095408_software_and_project_assets/migration.sql @@ -0,0 +1,91 @@ +-- CreateEnum +CREATE TYPE "SoftwareApprovalStatus" AS ENUM ('BEANTRAGT', 'FREIGEGEBEN', 'GESPERRT'); + +-- CreateEnum +CREATE TYPE "ProjectStatus" AS ENUM ('GEPLANT', 'LAUFEND', 'ABGESCHLOSSEN', 'ABGEBROCHEN'); + +-- AlterEnum +-- This migration adds more than one value to an enum. +-- With PostgreSQL versions 11 and earlier, this is not possible +-- in a single migration. This can be worked around by creating +-- multiple migrations, each migration adding only one value to +-- the enum. + + +ALTER TYPE "AssetType" ADD VALUE 'SOFTWARE'; +ALTER TYPE "AssetType" ADD VALUE 'PROJECT'; + +-- CreateTable +CREATE TABLE "software_profiles" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "provider_asset_id" TEXT, + "version" TEXT, + "approval_status" "SoftwareApprovalStatus" NOT NULL DEFAULT 'BEANTRAGT', + "approved_by" TEXT, + "criticality" INTEGER NOT NULL DEFAULT 1, + "next_review" TIMESTAMP(3), + "notes" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "software_profiles_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "project_profiles" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + "ref_no" INTEGER NOT NULL, + "classification" TEXT, + "isb_involved" BOOLEAN NOT NULL DEFAULT false, + "status" "ProjectStatus" NOT NULL DEFAULT 'GEPLANT', + "notes" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_by" TEXT, + + CONSTRAINT "project_profiles_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "software_profiles_asset_id_key" ON "software_profiles"("asset_id"); + +-- CreateIndex +CREATE INDEX "software_profiles_tenant_id_idx" ON "software_profiles"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "software_profiles_tenant_id_ref_no_key" ON "software_profiles"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE UNIQUE INDEX "project_profiles_asset_id_key" ON "project_profiles"("asset_id"); + +-- CreateIndex +CREATE INDEX "project_profiles_tenant_id_idx" ON "project_profiles"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "project_profiles_tenant_id_ref_no_key" ON "project_profiles"("tenant_id", "ref_no"); + +-- AddForeignKey +ALTER TABLE "software_profiles" ADD CONSTRAINT "software_profiles_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "software_profiles" ADD CONSTRAINT "software_profiles_provider_asset_id_fkey" FOREIGN KEY ("provider_asset_id") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "project_profiles" ADD CONSTRAINT "project_profiles_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- RLS für die neuen mandantenbezogenen Tabellen. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['software_profiles','project_profiles'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260728104412_tasks_wizard_fields/migration.sql b/prisma/migrations/20260728104412_tasks_wizard_fields/migration.sql new file mode 100644 index 0000000..a2e5c9a --- /dev/null +++ b/prisma/migrations/20260728104412_tasks_wizard_fields/migration.sql @@ -0,0 +1,6 @@ +-- AlterTable +ALTER TABLE "tasks" ADD COLUMN "links" JSONB, +ADD COLUMN "origin" TEXT, +ADD COLUMN "priority" TEXT NOT NULL DEFAULT 'mittel', +ADD COLUMN "resources" JSONB; + diff --git a/prisma/migrations/20260728105241_onboarding_progress/migration.sql b/prisma/migrations/20260728105241_onboarding_progress/migration.sql new file mode 100644 index 0000000..e6f8706 --- /dev/null +++ b/prisma/migrations/20260728105241_onboarding_progress/migration.sql @@ -0,0 +1,32 @@ +-- CreateEnum +CREATE TYPE "OnboardingStepStatus" AS ENUM ('offen', 'in_bearbeitung', 'zur_validierung', 'validiert'); + +-- CreateTable +CREATE TABLE "onboarding_progress" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "step_key" TEXT NOT NULL, + "status" "OnboardingStepStatus" NOT NULL DEFAULT 'offen', + "review_comment" TEXT, + "reviewer_id" TEXT, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "onboarding_progress_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "onboarding_progress_tenant_id_idx" ON "onboarding_progress"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "onboarding_progress_tenant_id_step_key_key" ON "onboarding_progress"("tenant_id", "step_key"); + +-- RLS für die neue mandantenbezogene Tabelle. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['onboarding_progress'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260728115109_object_review_status/migration.sql b/prisma/migrations/20260728115109_object_review_status/migration.sql new file mode 100644 index 0000000..a02d7e6 --- /dev/null +++ b/prisma/migrations/20260728115109_object_review_status/migration.sql @@ -0,0 +1,12 @@ +-- Generalisiertes Review-Status-Enum (Story F2, Contracts §2). Ersetzt das +-- schrittbezogene OnboardingStepStatus und ergänzt den Zustand `zurueckgewiesen`. +-- CreateEnum +CREATE TYPE "ObjectReviewStatus" AS ENUM ('offen', 'in_bearbeitung', 'zur_validierung', 'validiert', 'zurueckgewiesen'); + +-- AlterTable: onboarding_progress.status auf das neue Enum umziehen (werterhaltend) +ALTER TABLE "onboarding_progress" ALTER COLUMN "status" DROP DEFAULT; +ALTER TABLE "onboarding_progress" ALTER COLUMN "status" TYPE "ObjectReviewStatus" USING ("status"::text::"ObjectReviewStatus"); +ALTER TABLE "onboarding_progress" ALTER COLUMN "status" SET DEFAULT 'offen'; + +-- DropEnum: altes, schrittbezogenes Enum entfernen +DROP TYPE "OnboardingStepStatus"; diff --git a/prisma/migrations/20260728122213_wizard_facts/migration.sql b/prisma/migrations/20260728122213_wizard_facts/migration.sql new file mode 100644 index 0000000..76d2205 --- /dev/null +++ b/prisma/migrations/20260728122213_wizard_facts/migration.sql @@ -0,0 +1,29 @@ +-- CreateTable +CREATE TABLE "wizard_facts" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "key" TEXT NOT NULL, + "section" TEXT NOT NULL, + "value" JSONB NOT NULL, + "updated_at" TIMESTAMP(3) NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "wizard_facts_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "wizard_facts_tenant_id_idx" ON "wizard_facts"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "wizard_facts_tenant_id_key_key" ON "wizard_facts"("tenant_id", "key"); + + +-- RLS für die neue mandantenbezogene Tabelle. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['wizard_facts'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260728153225_wizard_scope/migration.sql b/prisma/migrations/20260728153225_wizard_scope/migration.sql new file mode 100644 index 0000000..be30d29 --- /dev/null +++ b/prisma/migrations/20260728153225_wizard_scope/migration.sql @@ -0,0 +1,30 @@ +-- CreateTable +CREATE TABLE "wizard_scopes" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "pruefziele" TEXT[] DEFAULT ARRAY['informationssicherheit']::TEXT[], + "geltungsbereich" TEXT, + "standorte" TEXT[] DEFAULT ARRAY[]::TEXT[], + "ausschluesse" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "wizard_scopes_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "wizard_scopes_tenant_id_key" ON "wizard_scopes"("tenant_id"); + +-- CreateIndex +CREATE INDEX "wizard_scopes_tenant_id_idx" ON "wizard_scopes"("tenant_id"); + + +-- RLS für die neue mandantenbezogene Tabelle. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['wizard_scopes'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260728154046_implementation_hints/migration.sql b/prisma/migrations/20260728154046_implementation_hints/migration.sql new file mode 100644 index 0000000..531fd4a --- /dev/null +++ b/prisma/migrations/20260728154046_implementation_hints/migration.sql @@ -0,0 +1,25 @@ +-- CreateTable +CREATE TABLE "implementation_hints" ( + "id" TEXT NOT NULL, + "req_id" TEXT NOT NULL, + "control" TEXT NOT NULL, + "stufe" TEXT NOT NULL, + "requirement" TEXT NOT NULL, + "organisational" TEXT NOT NULL, + "technical" TEXT NOT NULL, + "evidence" TEXT NOT NULL, + "template" TEXT, + "resources" TEXT NOT NULL, + "al_filter" TEXT NOT NULL, + "procurement" BOOLEAN NOT NULL DEFAULT false, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "implementation_hints_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "implementation_hints_req_id_key" ON "implementation_hints"("req_id"); + +-- CreateIndex +CREATE INDEX "implementation_hints_control_idx" ON "implementation_hints"("control"); + diff --git a/prisma/migrations/20260728161306_policy_package_state/migration.sql b/prisma/migrations/20260728161306_policy_package_state/migration.sql new file mode 100644 index 0000000..8d5d65a --- /dev/null +++ b/prisma/migrations/20260728161306_policy_package_state/migration.sql @@ -0,0 +1,27 @@ +-- CreateTable +CREATE TABLE "policy_package_states" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "imported_version" TEXT, + "imported_at" TIMESTAMP(3), + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "policy_package_states_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_package_states_tenant_id_key" ON "policy_package_states"("tenant_id"); + +-- CreateIndex +CREATE INDEX "policy_package_states_tenant_id_idx" ON "policy_package_states"("tenant_id"); + + +-- RLS für die neue mandantenbezogene Tabelle. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['policy_package_states'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260729101027_risk_catalog/migration.sql b/prisma/migrations/20260729101027_risk_catalog/migration.sql new file mode 100644 index 0000000..84f22d4 --- /dev/null +++ b/prisma/migrations/20260729101027_risk_catalog/migration.sql @@ -0,0 +1,28 @@ +-- AlterTable +ALTER TABLE "risks" ADD COLUMN "catalog_code" TEXT; + +-- CreateTable +CREATE TABLE "risk_catalog_entries" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "category" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT NOT NULL, + "controls" TEXT[] DEFAULT ARRAY[]::TEXT[], + "asset_types" TEXT[] DEFAULT ARRAY[]::TEXT[], + "standard_measure" TEXT NOT NULL, + "default_likelihood" INTEGER NOT NULL, + "default_impact" INTEGER NOT NULL, + "rationale" TEXT NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "risk_catalog_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "risk_catalog_entries_code_key" ON "risk_catalog_entries"("code"); + +-- CreateIndex +CREATE INDEX "risk_catalog_entries_category_idx" ON "risk_catalog_entries"("category"); + diff --git a/prisma/migrations/20260729103725_risk_acceptance/migration.sql b/prisma/migrations/20260729103725_risk_acceptance/migration.sql new file mode 100644 index 0000000..f3e3f91 --- /dev/null +++ b/prisma/migrations/20260729103725_risk_acceptance/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "risks" ADD COLUMN "acceptance_rationale" TEXT, +ADD COLUMN "accepted_at" TIMESTAMP(3), +ADD COLUMN "accepted_by_id" TEXT; + diff --git a/prisma/migrations/20260729120000_control_assessments/migration.sql b/prisma/migrations/20260729120000_control_assessments/migration.sql new file mode 100644 index 0000000..da59ac1 --- /dev/null +++ b/prisma/migrations/20260729120000_control_assessments/migration.sql @@ -0,0 +1,35 @@ +-- CreateTable +CREATE TABLE "control_assessments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "control" TEXT NOT NULL, + "suggested_value" INTEGER, + "confirmed_value" INTEGER NOT NULL, + "target" INTEGER NOT NULL, + "justification" TEXT, + "confirmed_by_id" TEXT, + "confirmed_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "control_assessments_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "control_assessments_tenant_id_idx" ON "control_assessments"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "control_assessments_tenant_id_control_key" ON "control_assessments"("tenant_id", "control"); + + +-- Row Level Security (zweite Verteidigungslinie, analog übrige Mandanten-Tabellen) +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['control_assessments'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format( + 'CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', + t + ); + END LOOP; +END $$; diff --git a/prisma/migrations/20260729140000_task_description/migration.sql b/prisma/migrations/20260729140000_task_description/migration.sql new file mode 100644 index 0000000..7a87330 --- /dev/null +++ b/prisma/migrations/20260729140000_task_description/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "tasks" ADD COLUMN "description" TEXT; + diff --git a/prisma/migrations/20260729150000_control_implementations/migration.sql b/prisma/migrations/20260729150000_control_implementations/migration.sql new file mode 100644 index 0000000..b132ce2 --- /dev/null +++ b/prisma/migrations/20260729150000_control_implementations/migration.sql @@ -0,0 +1,36 @@ +-- CreateTable +CREATE TABLE "control_implementations" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "req_id" TEXT NOT NULL, + "control" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'offen', + "note" TEXT, + "updated_by_id" TEXT, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "control_implementations_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "control_implementations_tenant_id_idx" ON "control_implementations"("tenant_id"); + +-- CreateIndex +CREATE INDEX "control_implementations_tenant_id_control_idx" ON "control_implementations"("tenant_id", "control"); + +-- CreateIndex +CREATE UNIQUE INDEX "control_implementations_tenant_id_req_id_key" ON "control_implementations"("tenant_id", "req_id"); + + +-- Row Level Security (zweite Verteidigungslinie, analog übrige Mandanten-Tabellen) +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['control_implementations'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format( + 'CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', + t + ); + END LOOP; +END $$; diff --git a/prisma/migrations/20260730111105_login_lockout/migration.sql b/prisma/migrations/20260730111105_login_lockout/migration.sql new file mode 100644 index 0000000..bf6f883 --- /dev/null +++ b/prisma/migrations/20260730111105_login_lockout/migration.sql @@ -0,0 +1,9 @@ +-- F-05: Brute-Force-Schutz Mandanten-Login — Fehlversuchszähler + Kontosperre. +-- Nur eigene DDL (die geteilte lokale DB kann fremde Branch-Änderungen enthalten; +-- diese wurden bewusst NICHT übernommen). Die Tabelle "users" hat bereits eine +-- aktive RLS-Policy (tenant_isolation, Migration 20260702095816); das Hinzufügen +-- von Spalten erfordert keinen neuen RLS-DO-Block. + +-- AlterTable +ALTER TABLE "users" ADD COLUMN "failed_logins" INTEGER NOT NULL DEFAULT 0, +ADD COLUMN "locked_until" TIMESTAMP(3); diff --git a/prisma/migrations/20260730160000_rls_enforce/migration.sql b/prisma/migrations/20260730160000_rls_enforce/migration.sql new file mode 100644 index 0000000..6a4d110 --- /dev/null +++ b/prisma/migrations/20260730160000_rls_enforce/migration.sql @@ -0,0 +1,391 @@ +-- ============================================================================ +-- F-04: Row Level Security scharfschalten (FORCE + WITH CHECK + Kontext) +-- ============================================================================ +-- Diese Migration enthält NUR SQL (keine Schemaänderung) und ist idempotent. +-- +-- Ziel: Die in den bisherigen Migrationen definierten `tenant_isolation`-Policies +-- werden für die eingeschränkte App-Rolle `isms_app` (NOBYPASSRLS) wirksam. +-- +-- Warum FORCE für den Owner UNSCHÄDLICH ist: +-- PostgreSQL wendet RLS auf einen Superuser bzw. eine Rolle mit BYPASSRLS NIE +-- an — auch nicht unter FORCE ROW LEVEL SECURITY. Die Owner-/Migrations-Rolle +-- `isms` ist Superuser + BYPASSRLS, sieht also weiterhin ALLE Zeilen. Deshalb +-- bleiben Migrationen, Seed und der mandantenübergreifende Login-Lookup (die +-- über `DATABASE_URL` = Owner laufen) voll funktionsfähig. FORCE greift nur für +-- `isms_app`. WICHTIG für Prod: Die Owner-/Migrate-Rolle MUSS BYPASSRLS bzw. +-- Superuser sein, sonst sähe der Login keine Nutzer (null Zeilen). +-- +-- Warum WITH CHECK zwingend nötig ist (INSERT-Falle): +-- Unter FORCE ROW LEVEL SECURITY lehnt Postgres jeden INSERT/UPDATE ab, dessen +-- Zielzeile keine WITH-CHECK-Policy erfüllt. Die bisherigen Policies hatten nur +-- USING (Lesefilter), KEIN WITH CHECK → damit würde `isms_app` KEINE Zeile mehr +-- anlegen können. Jede Policy erhält deshalb hier zusätzlich +-- `WITH CHECK (tenant_id = current_setting('app.tenant_id', true))`, sodass nur +-- Zeilen des aktiven Mandanten geschrieben werden dürfen (verhindert auch das +-- „Umschreiben" einer Zeile auf einen fremden Mandanten). +-- +-- Wie der Kontext gesetzt wird: +-- `current_setting('app.tenant_id', true)` liest den GUC-Parameter (2. Arg true +-- = kein Fehler, wenn ungesetzt → NULL). Die App setzt ihn TRANSAKTIONSLOKAL via +-- `SELECT set_config('app.tenant_id', <tenantId>, true)` in derselben Transaktion +-- wie die eigentliche Operation (siehe src/server/db.ts, dbForTenant, RLS-Pfad). +-- Ist der Kontext NICHT gesetzt, ergibt `tenant_id = NULL` → NULL (nicht TRUE): +-- `isms_app` sieht dann 0 Zeilen (fail-closed). Genau deshalb MUSS das +-- Scharfschalten zusammen mit der Kontextsetzung (RLS_ENFORCED=true) erfolgen. +-- +-- App-Rolle / Secret (NICHT in dieser Migration): +-- `isms_app` existiert bereits (NOLOGIN, NOBYPASSRLS, mit GRANTs). Für den +-- scharfen Betrieb braucht sie LOGIN + starkes Passwort — das ist ein SECRET und +-- gehört NICHT in versioniertes SQL. Setze es operativ (einmalig), z. B.: +-- ALTER ROLE isms_app WITH LOGIN PASSWORD '<stark>'; +-- und verbinde die App über RLS_DATABASE_URL als isms_app (RLS_ENFORCED=true). +-- Siehe docs/DEPLOY-PROD-CONTABO.md und .env.prod.example. +-- +-- Idempotenz: ENABLE/FORCE sind idempotent; die Policy wird vor CREATE via +-- DROP POLICY IF EXISTS entfernt (deckt Gruppe A = 12 bestehende USING-only- +-- Policies und Gruppe B = 37 ohne Policy einheitlich ab). +-- ============================================================================ + +ALTER TABLE "asset_relations" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "asset_relations"; +CREATE POLICY tenant_isolation ON "asset_relations" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "asset_relations" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "assets" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "assets"; +CREATE POLICY tenant_isolation ON "assets" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "assets" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "audit_logs" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "audit_logs"; +CREATE POLICY tenant_isolation ON "audit_logs" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "audit_logs" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "bia_entries" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "bia_entries"; +CREATE POLICY tenant_isolation ON "bia_entries" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "bia_entries" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "measures" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "measures"; +CREATE POLICY tenant_isolation ON "measures" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "measures" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "process_assets" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "process_assets"; +CREATE POLICY tenant_isolation ON "process_assets" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "process_assets" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "processes" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "processes"; +CREATE POLICY tenant_isolation ON "processes" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "processes" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "risk_assets" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "risk_assets"; +CREATE POLICY tenant_isolation ON "risk_assets" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "risk_assets" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "risk_measures" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "risk_measures"; +CREATE POLICY tenant_isolation ON "risk_measures" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "risk_measures" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "risks" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "risks"; +CREATE POLICY tenant_isolation ON "risks" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "risks" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "roles" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "roles"; +CREATE POLICY tenant_isolation ON "roles" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "roles" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "users" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "users"; +CREATE POLICY tenant_isolation ON "users" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "users" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "tasks" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "tasks"; +CREATE POLICY tenant_isolation ON "tasks" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "tasks" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "task_comments" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "task_comments"; +CREATE POLICY tenant_isolation ON "task_comments" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "task_comments" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "managed_registers" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "managed_registers"; +CREATE POLICY tenant_isolation ON "managed_registers" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "managed_registers" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "register_rows" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "register_rows"; +CREATE POLICY tenant_isolation ON "register_rows" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "register_rows" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "onboarding_progress" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "onboarding_progress"; +CREATE POLICY tenant_isolation ON "onboarding_progress" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "onboarding_progress" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "wizard_facts" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "wizard_facts"; +CREATE POLICY tenant_isolation ON "wizard_facts" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "wizard_facts" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "wizard_scopes" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "wizard_scopes"; +CREATE POLICY tenant_isolation ON "wizard_scopes" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "wizard_scopes" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "policy_package_states" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_package_states"; +CREATE POLICY tenant_isolation ON "policy_package_states" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_package_states" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "tenant_settings" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "tenant_settings"; +CREATE POLICY tenant_isolation ON "tenant_settings" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "tenant_settings" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "tenant_modules" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "tenant_modules"; +CREATE POLICY tenant_isolation ON "tenant_modules" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "tenant_modules" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "supplier_profiles" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "supplier_profiles"; +CREATE POLICY tenant_isolation ON "supplier_profiles" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "supplier_profiles" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "it_service_profiles" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "it_service_profiles"; +CREATE POLICY tenant_isolation ON "it_service_profiles" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "it_service_profiles" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "software_profiles" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "software_profiles"; +CREATE POLICY tenant_isolation ON "software_profiles" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "software_profiles" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "project_profiles" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "project_profiles"; +CREATE POLICY tenant_isolation ON "project_profiles" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "project_profiles" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "supplier_assessments" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "supplier_assessments"; +CREATE POLICY tenant_isolation ON "supplier_assessments" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "supplier_assessments" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "contracts" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "contracts"; +CREATE POLICY tenant_isolation ON "contracts" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "contracts" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "ndas" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "ndas"; +CREATE POLICY tenant_isolation ON "ndas" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "ndas" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "supplier_evidence" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "supplier_evidence"; +CREATE POLICY tenant_isolation ON "supplier_evidence" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "supplier_evidence" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "service_control_responsibilities" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "service_control_responsibilities"; +CREATE POLICY tenant_isolation ON "service_control_responsibilities" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "service_control_responsibilities" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "subcontractors" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "subcontractors"; +CREATE POLICY tenant_isolation ON "subcontractors" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "subcontractors" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "management_decisions" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "management_decisions"; +CREATE POLICY tenant_isolation ON "management_decisions" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "management_decisions" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "maturity_assessments" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "maturity_assessments"; +CREATE POLICY tenant_isolation ON "maturity_assessments" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "maturity_assessments" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "control_assessments" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "control_assessments"; +CREATE POLICY tenant_isolation ON "control_assessments" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "control_assessments" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "control_implementations" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "control_implementations"; +CREATE POLICY tenant_isolation ON "control_implementations" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "control_implementations" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "policy_documents" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_documents"; +CREATE POLICY tenant_isolation ON "policy_documents" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_documents" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "policy_requirements" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_requirements"; +CREATE POLICY tenant_isolation ON "policy_requirements" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_requirements" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "policy_variables" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_variables"; +CREATE POLICY tenant_isolation ON "policy_variables" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_variables" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "policy_baseline_params" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_baseline_params"; +CREATE POLICY tenant_isolation ON "policy_baseline_params" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_baseline_params" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "policy_evidence" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_evidence"; +CREATE POLICY tenant_isolation ON "policy_evidence" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_evidence" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "crypto_entries" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "crypto_entries"; +CREATE POLICY tenant_isolation ON "crypto_entries" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "crypto_entries" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "classification_classes" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "classification_classes"; +CREATE POLICY tenant_isolation ON "classification_classes" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "classification_classes" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "handling_aspects" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "handling_aspects"; +CREATE POLICY tenant_isolation ON "handling_aspects" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "handling_aspects" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "handling_rules" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "handling_rules"; +CREATE POLICY tenant_isolation ON "handling_rules" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "handling_rules" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "risk_matrix_classes" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "risk_matrix_classes"; +CREATE POLICY tenant_isolation ON "risk_matrix_classes" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "risk_matrix_classes" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "risk_ew_levels" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "risk_ew_levels"; +CREATE POLICY tenant_isolation ON "risk_ew_levels" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "risk_ew_levels" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "risk_damage_dimensions" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "risk_damage_dimensions"; +CREATE POLICY tenant_isolation ON "risk_damage_dimensions" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "risk_damage_dimensions" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "handbook_topics" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "handbook_topics"; +CREATE POLICY tenant_isolation ON "handbook_topics" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "handbook_topics" FORCE ROW LEVEL SECURITY; + diff --git a/prisma/migrations/20260730170000_mfa_totp_replay/migration.sql b/prisma/migrations/20260730170000_mfa_totp_replay/migration.sql new file mode 100644 index 0000000..1419426 --- /dev/null +++ b/prisma/migrations/20260730170000_mfa_totp_replay/migration.sql @@ -0,0 +1,14 @@ +-- F-17: TOTP-Replay-Schutz — zuletzt akzeptierter RFC-6238-Zeitschritt je Identität. +-- Ein bereits verwendeter (oder älterer) Zeitschritt wird beim Login/2FA abgelehnt. +-- +-- Nur EIGENE DDL (die geteilte lokale DB kann Änderungen paralleler Branches +-- enthalten; fremde Blöcke wurden bewusst NICHT übernommen). "users" hat bereits +-- eine aktive RLS-Policy (tenant_isolation, Migration 20260702095816); das reine +-- Hinzufügen einer Spalte erfordert keinen neuen RLS-DO-Block. "platform_admins" +-- ist plattformweit (kein tenant_id/RLS). + +-- AlterTable +ALTER TABLE "platform_admins" ADD COLUMN "last_totp_step" BIGINT; + +-- AlterTable +ALTER TABLE "users" ADD COLUMN "last_totp_step" BIGINT; diff --git a/prisma/migrations/20260730180000_mail_fundament/migration.sql b/prisma/migrations/20260730180000_mail_fundament/migration.sql new file mode 100644 index 0000000..d9e4375 --- /dev/null +++ b/prisma/migrations/20260730180000_mail_fundament/migration.sql @@ -0,0 +1,84 @@ +-- CreateTable +CREATE TABLE "mail_logs" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT, + "scope" TEXT NOT NULL DEFAULT 'tenant', + "to" TEXT NOT NULL, + "template" TEXT NOT NULL, + "locale" TEXT NOT NULL DEFAULT 'de', + "status" TEXT NOT NULL DEFAULT 'pending', + "provider_message_id" TEXT, + "error" TEXT, + "attempts" INTEGER NOT NULL DEFAULT 0, + "dedupe_key" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "sent_at" TIMESTAMP(3), + + CONSTRAINT "mail_logs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "notification_preferences" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "event_type" TEXT NOT NULL, + "email" BOOLEAN NOT NULL DEFAULT true, + "locale" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "notification_preferences_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "mail_logs_dedupe_key_key" ON "mail_logs"("dedupe_key"); + +-- CreateIndex +CREATE INDEX "mail_logs_tenant_id_created_at_idx" ON "mail_logs"("tenant_id", "created_at"); + +-- CreateIndex +CREATE INDEX "mail_logs_status_idx" ON "mail_logs"("status"); + +-- CreateIndex +CREATE INDEX "notification_preferences_tenant_id_idx" ON "notification_preferences"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "notification_preferences_user_id_event_type_key" ON "notification_preferences"("user_id", "event_type"); + + +-- ============================================================================ +-- Row Level Security (SEC1) +-- +-- Muster wie seit F-04 (20260730160000_rls_enforce): ENABLE + FORCE + Policy mit +-- USING *und* WITH CHECK. Ohne WITH CHECK koennte die eingeschraenkte App-Rolle +-- `isms_app` unter FORCE keine Zeilen mehr anlegen. +-- +-- mail_logs.tenant_id ist NULLABLE (Plattform-Mails ohne Mandantenbezug). Die +-- Policy ist trotzdem identisch zu audit_logs, das dieselbe Situation hat: +-- Zeilen mit tenant_id = NULL erfuellen die Bedingung nie und sind fuer `isms_app` +-- weder les- noch schreibbar. Das ist beabsichtigt — Plattform-Zeilen werden +-- ausschliesslich ueber den rohen `prisma`-Client (Owner-Rolle, BYPASSRLS) +-- geschrieben, genau wie writePlatformAudit(). +-- +-- GRANT ist noetig, weil die pauschalen Rechte aus 20260702095816 nur fuer die +-- damals existierenden Tabellen galten; ALTER DEFAULT PRIVILEGES greift nur fuer +-- Objekte, die von der dort gesetzten Rolle erzeugt werden. +-- ============================================================================ + +GRANT SELECT, INSERT, UPDATE, DELETE ON "mail_logs" TO isms_app; +GRANT SELECT, INSERT, UPDATE, DELETE ON "notification_preferences" TO isms_app; + +ALTER TABLE "mail_logs" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "mail_logs"; +CREATE POLICY tenant_isolation ON "mail_logs" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "mail_logs" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "notification_preferences" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "notification_preferences"; +CREATE POLICY tenant_isolation ON "notification_preferences" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "notification_preferences" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260730190000_auth_tokens_sessions/migration.sql b/prisma/migrations/20260730190000_auth_tokens_sessions/migration.sql new file mode 100644 index 0000000..2b0a13b --- /dev/null +++ b/prisma/migrations/20260730190000_auth_tokens_sessions/migration.sql @@ -0,0 +1,57 @@ +-- AlterTable +ALTER TABLE "platform_admins" ADD COLUMN "sessions_valid_after" TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "users" ADD COLUMN "sessions_valid_after" TIMESTAMP(3); + +-- CreateTable +CREATE TABLE "auth_tokens" ( + "id" TEXT NOT NULL, + "principal_type" TEXT NOT NULL, + "principal_id" TEXT NOT NULL, + "tenant_id" TEXT, + "type" TEXT NOT NULL, + "token_hash" TEXT NOT NULL, + "new_email" TEXT, + "expires_at" TIMESTAMP(3) NOT NULL, + "used_at" TIMESTAMP(3), + "request_ip" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "auth_tokens_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "auth_tokens_token_hash_key" ON "auth_tokens"("token_hash"); + +-- CreateIndex +CREATE INDEX "auth_tokens_principal_type_principal_id_type_idx" ON "auth_tokens"("principal_type", "principal_id", "type"); + +-- CreateIndex +CREATE INDEX "auth_tokens_expires_at_idx" ON "auth_tokens"("expires_at"); + + +-- ============================================================================ +-- Row Level Security (SEC2) +-- +-- Muster wie seit F-04: ENABLE + FORCE + Policy mit USING *und* WITH CHECK. +-- +-- auth_tokens.tenant_id ist NULLABLE (Plattform-Admin-Tokens ohne +-- Mandantenbezug) — dieselbe Situation wie bei audit_logs und mail_logs. Zeilen +-- mit tenant_id = NULL sind fuer `isms_app` weder les- noch schreibbar. +-- +-- WICHTIG: Der Token-Lookup beim Einloesen laeuft ohne Session (der Nutzer ist +-- gerade nicht angemeldet) und damit ohne Mandantenkontext. Er erfolgt deshalb +-- bewusst ueber den rohen `prisma`-Client (Owner-Rolle, BYPASSRLS) — siehe +-- src/server/auth-token.ts. Die Policy bleibt als zweite Verteidigungslinie +-- gegen versehentliche Zugriffe ueber den Mandanten-Guard bestehen. +-- ============================================================================ + +GRANT SELECT, INSERT, UPDATE, DELETE ON "auth_tokens" TO isms_app; + +ALTER TABLE "auth_tokens" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "auth_tokens"; +CREATE POLICY tenant_isolation ON "auth_tokens" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "auth_tokens" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260731120000_webauthn_credentials/migration.sql b/prisma/migrations/20260731120000_webauthn_credentials/migration.sql new file mode 100644 index 0000000..c0ca3f5 --- /dev/null +++ b/prisma/migrations/20260731120000_webauthn_credentials/migration.sql @@ -0,0 +1,38 @@ +-- CreateTable +CREATE TABLE "webauthn_credentials" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "credential_id" TEXT NOT NULL, + "public_key" TEXT NOT NULL, + "counter" BIGINT NOT NULL DEFAULT 0, + "transports" TEXT[] DEFAULT ARRAY[]::TEXT[], + "device_name" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "last_used_at" TIMESTAMP(3), + + CONSTRAINT "webauthn_credentials_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "webauthn_credentials_credential_id_key" ON "webauthn_credentials"("credential_id"); + +-- CreateIndex +CREATE INDEX "webauthn_credentials_tenant_id_idx" ON "webauthn_credentials"("tenant_id"); + +-- CreateIndex +CREATE INDEX "webauthn_credentials_user_id_idx" ON "webauthn_credentials"("user_id"); + +-- AddForeignKey +ALTER TABLE "webauthn_credentials" ADD CONSTRAINT "webauthn_credentials_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- Row Level Security (analog übrige Mandanten-Tabellen) +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY['webauthn_credentials'] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260731123409_tisax_m0_foundation/migration.sql b/prisma/migrations/20260731123409_tisax_m0_foundation/migration.sql new file mode 100644 index 0000000..c2bc1e3 --- /dev/null +++ b/prisma/migrations/20260731123409_tisax_m0_foundation/migration.sql @@ -0,0 +1,15 @@ +-- CreateEnum +CREATE TYPE "Domain" AS ENUM ('GOVERNANCE', 'HR', 'PHYSICAL', 'BCM', 'IT', 'PROCUREMENT', 'COMPLIANCE', 'DATA_PROTECTION', 'PROTOTYPE'); + +-- CreateEnum +CREATE TYPE "RaciKind" AS ENUM ('RESPONSIBLE', 'ACCOUNTABLE', 'CONSULTED', 'INFORMED'); + +-- CreateEnum +CREATE TYPE "InfoLabel" AS ENUM ('NONE', 'INFO_HIGH', 'INFO_VERY_HIGH', 'PROTOTYPE', 'PERSONAL_DATA'); + +-- AlterTable +ALTER TABLE "tasks" ADD COLUMN "domain" "Domain", +ADD COLUMN "order_idx" INTEGER NOT NULL DEFAULT 0; + +-- CreateIndex +CREATE INDEX "tasks_tenant_id_domain_status_idx" ON "tasks"("tenant_id", "domain", "status"); diff --git a/prisma/migrations/20260731130000_platform_admin_role/migration.sql b/prisma/migrations/20260731130000_platform_admin_role/migration.sql new file mode 100644 index 0000000..4570068 --- /dev/null +++ b/prisma/migrations/20260731130000_platform_admin_role/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "platform_admins" ADD COLUMN "role" TEXT NOT NULL DEFAULT 'full'; + diff --git a/prisma/migrations/20260731152213_tisax_m1_m4_consolidated/migration.sql b/prisma/migrations/20260731152213_tisax_m1_m4_consolidated/migration.sql new file mode 100644 index 0000000..36a1e34 --- /dev/null +++ b/prisma/migrations/20260731152213_tisax_m1_m4_consolidated/migration.sql @@ -0,0 +1,136 @@ +-- AlterTable +ALTER TABLE "assets" ADD COLUMN "label" "InfoLabel" NOT NULL DEFAULT 'NONE', +ADD COLUMN "normalized_name" TEXT; + +-- AlterTable +ALTER TABLE "tasks" ADD COLUMN "effective_until" TIMESTAMP(3), +ADD COLUMN "recurrence" TEXT, +ADD COLUMN "remind_at" TIMESTAMP(3); + +-- CreateTable +CREATE TABLE "process_catalog" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "name" TEXT NOT NULL, + "category" "ProcessCategory" NOT NULL, + "suggested_asset_types" "AssetType"[], + "suggested_risk_codes" TEXT[] DEFAULT ARRAY[]::TEXT[], + "suggested_info_labels" "InfoLabel"[], + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "process_catalog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "task_participants" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "task_id" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "raci" "RaciKind" NOT NULL, + + CONSTRAINT "task_participants_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "control_domain_map" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT, + "control" TEXT NOT NULL, + "domain" "Domain" NOT NULL, + "raci" "RaciKind" NOT NULL DEFAULT 'RESPONSIBLE', + "function_key" TEXT, + + CONSTRAINT "control_domain_map_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "evidence" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "kind" TEXT NOT NULL, + "file_ref" TEXT, + "task_id" TEXT, + "control" TEXT, + "valid_from" TIMESTAMP(3), + "valid_until" TIMESTAMP(3), + "created_by_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "evidence_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "project_function_assignments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "function_key" TEXT NOT NULL, + "user_id" TEXT, + "domain" "Domain", + "invited_email" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "project_function_assignments_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "process_catalog_code_key" ON "process_catalog"("code"); + +-- CreateIndex +CREATE INDEX "task_participants_tenant_id_user_id_idx" ON "task_participants"("tenant_id", "user_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "task_participants_tenant_id_task_id_user_id_raci_key" ON "task_participants"("tenant_id", "task_id", "user_id", "raci"); + +-- CreateIndex +CREATE INDEX "control_domain_map_tenant_id_control_idx" ON "control_domain_map"("tenant_id", "control"); + +-- CreateIndex +CREATE INDEX "control_domain_map_control_idx" ON "control_domain_map"("control"); + +-- CreateIndex +CREATE INDEX "evidence_tenant_id_control_idx" ON "evidence"("tenant_id", "control"); + +-- CreateIndex +CREATE INDEX "evidence_tenant_id_task_id_idx" ON "evidence"("tenant_id", "task_id"); + +-- CreateIndex +CREATE INDEX "project_function_assignments_tenant_id_function_key_idx" ON "project_function_assignments"("tenant_id", "function_key"); + +-- CreateIndex +CREATE UNIQUE INDEX "assets_tenant_id_normalized_name_key" ON "assets"("tenant_id", "normalized_name"); + +-- AddForeignKey +ALTER TABLE "task_participants" ADD CONSTRAINT "task_participants_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "evidence" ADD CONSTRAINT "evidence_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE SET NULL ON UPDATE CASCADE; + + +-- ── Tenant-Isolation (RLS) für neue mandantenbezogene Tabellen ─────────────── +-- Muster wie seit F-04: ENABLE + FORCE + Policy mit USING *und* WITH CHECK. +-- Globale Tabellen (process_catalog) und die tenant-optionale control_domain_map +-- (globale Defaults mit tenant_id = NULL) sind bewusst ausgenommen. +ALTER TABLE "project_function_assignments" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "project_function_assignments"; +CREATE POLICY tenant_isolation ON "project_function_assignments" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "project_function_assignments" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "task_participants" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "task_participants"; +CREATE POLICY tenant_isolation ON "task_participants" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "task_participants" FORCE ROW LEVEL SECURITY; + +ALTER TABLE "evidence" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "evidence"; +CREATE POLICY tenant_isolation ON "evidence" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "evidence" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260731154215_tisax_rekey_onboarding_steps/migration.sql b/prisma/migrations/20260731154215_tisax_rekey_onboarding_steps/migration.sql new file mode 100644 index 0000000..d668851 --- /dev/null +++ b/prisma/migrations/20260731154215_tisax_rekey_onboarding_steps/migration.sql @@ -0,0 +1,18 @@ +-- TISAX M1: Onboarding-Step-Keys umbenannt (scoping→scope, policies→policy). +-- Bestehende onboarding_progress-Zeilen umschlüsseln, damit der Fortschritt erhalten +-- bleibt (sonst verwaisen die Alt-Keys und die Schritte starten wieder als „offen"). +-- NOT EXISTS-Guard gegen die @@unique(tenant_id, step_key): existiert der Ziel-Key +-- bereits, wird nicht umbenannt (die neue Zeile gewinnt). +UPDATE "onboarding_progress" o SET "step_key" = 'scope' +WHERE o."step_key" = 'scoping' + AND NOT EXISTS ( + SELECT 1 FROM "onboarding_progress" i + WHERE i."tenant_id" = o."tenant_id" AND i."step_key" = 'scope' + ); + +UPDATE "onboarding_progress" o SET "step_key" = 'policy' +WHERE o."step_key" = 'policies' + AND NOT EXISTS ( + SELECT 1 FROM "onboarding_progress" i + WHERE i."tenant_id" = o."tenant_id" AND i."step_key" = 'policy' + ); diff --git a/prisma/migrations/20260731165818_tisax_v3_process_fields/migration.sql b/prisma/migrations/20260731165818_tisax_v3_process_fields/migration.sql new file mode 100644 index 0000000..833dc6b --- /dev/null +++ b/prisma/migrations/20260731165818_tisax_v3_process_fields/migration.sql @@ -0,0 +1,18 @@ +-- AlterTable +ALTER TABLE "processes" ADD COLUMN "bia_status" TEXT NOT NULL DEFAULT 'offen', +ADD COLUMN "catalog_code" TEXT, +ADD COLUMN "data_protection_relevant" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "deputy_owner_id" TEXT, +ADD COLUMN "in_scope" BOOLEAN NOT NULL DEFAULT true, +ADD COLUMN "interfaces" TEXT, +ADD COLUMN "legal_basis" TEXT, +ADD COLUMN "parent_id" TEXT, +ADD COLUMN "prototype_relevant" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "purpose" TEXT; + +-- CreateIndex +CREATE INDEX "processes_tenant_id_parent_id_idx" ON "processes"("tenant_id", "parent_id"); + +-- AddForeignKey +ALTER TABLE "processes" ADD CONSTRAINT "processes_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "processes"("id") ON DELETE SET NULL ON UPDATE CASCADE; + diff --git a/prisma/migrations/20260801134128_tisax_v4_catalog_parent/migration.sql b/prisma/migrations/20260801134128_tisax_v4_catalog_parent/migration.sql new file mode 100644 index 0000000..5b32242 --- /dev/null +++ b/prisma/migrations/20260801134128_tisax_v4_catalog_parent/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "process_catalog" ADD COLUMN "parent_code" TEXT; + diff --git a/prisma/migrations/20260804111342_tisax_v5_audit/migration.sql b/prisma/migrations/20260804111342_tisax_v5_audit/migration.sql new file mode 100644 index 0000000..3d0c2bf --- /dev/null +++ b/prisma/migrations/20260804111342_tisax_v5_audit/migration.sql @@ -0,0 +1,94 @@ +-- CreateEnum +CREATE TYPE "AuditType" AS ENUM ('INTERNAL', 'EXTERNAL'); + +-- CreateEnum +CREATE TYPE "AuditStatus" AS ENUM ('PLANNED', 'IN_PREPARATION', 'DONE'); + +-- CreateTable +CREATE TABLE "audits" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "type" "AuditType" NOT NULL, + "title" TEXT NOT NULL, + "planned_date" TEXT, + "scope" TEXT, + "assessment_level" TEXT, + "provider" TEXT, + "auditor_user_id" TEXT, + "status" "AuditStatus" NOT NULL DEFAULT 'PLANNED', + "preparation_deadline" TIMESTAMP(3), + "result" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "audits_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "audit_evidence_items" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "audit_id" TEXT NOT NULL, + "control" TEXT NOT NULL, + "title" TEXT NOT NULL, + "req_id" TEXT, + "assigned_user_id" TEXT, + "assigned_function_key" TEXT, + "status" TEXT NOT NULL DEFAULT 'offen', + "evidence_id" TEXT, + "task_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "audit_evidence_items_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "control_descriptions" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "control" TEXT NOT NULL, + "req_id" TEXT NOT NULL, + "draft_text" TEXT, + "source_ref" TEXT, + "confidence" TEXT, + "status" TEXT NOT NULL DEFAULT 'open', + "open_answer" TEXT, + "updated_by_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "control_descriptions_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "audits_tenant_id_status_idx" ON "audits"("tenant_id", "status"); + +-- CreateIndex +CREATE INDEX "audit_evidence_items_tenant_id_audit_id_idx" ON "audit_evidence_items"("tenant_id", "audit_id"); + +-- CreateIndex +CREATE INDEX "audit_evidence_items_tenant_id_assigned_user_id_status_idx" ON "audit_evidence_items"("tenant_id", "assigned_user_id", "status"); + +-- CreateIndex +CREATE INDEX "control_descriptions_tenant_id_control_idx" ON "control_descriptions"("tenant_id", "control"); + +-- CreateIndex +CREATE UNIQUE INDEX "control_descriptions_tenant_id_req_id_key" ON "control_descriptions"("tenant_id", "req_id"); + +-- AddForeignKey +ALTER TABLE "audit_evidence_items" ADD CONSTRAINT "audit_evidence_items_audit_id_fkey" FOREIGN KEY ("audit_id") REFERENCES "audits"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- ── Tenant-Isolation (RLS) für neue Audit-Tabellen (Muster wie F-04) ────────── +ALTER TABLE "audits" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "audits"; +CREATE POLICY tenant_isolation ON "audits" USING ("tenant_id" = current_setting('app.tenant_id', true)) WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "audits" FORCE ROW LEVEL SECURITY; +ALTER TABLE "audit_evidence_items" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "audit_evidence_items"; +CREATE POLICY tenant_isolation ON "audit_evidence_items" USING ("tenant_id" = current_setting('app.tenant_id', true)) WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "audit_evidence_items" FORCE ROW LEVEL SECURITY; +ALTER TABLE "control_descriptions" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "control_descriptions"; +CREATE POLICY tenant_isolation ON "control_descriptions" USING ("tenant_id" = current_setting('app.tenant_id', true)) WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "control_descriptions" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260805093503_tisax_v7_policy_domain/migration.sql b/prisma/migrations/20260805093503_tisax_v7_policy_domain/migration.sql new file mode 100644 index 0000000..4b16200 --- /dev/null +++ b/prisma/migrations/20260805093503_tisax_v7_policy_domain/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "policy_documents" ADD COLUMN "domain" "Domain"; + diff --git a/prisma/migrations/20260810120000_policy_templates/migration.sql b/prisma/migrations/20260810120000_policy_templates/migration.sql new file mode 100644 index 0000000..af78521 --- /dev/null +++ b/prisma/migrations/20260810120000_policy_templates/migration.sql @@ -0,0 +1,158 @@ +-- Globale Richtlinien-Vorlagen (Plattform-Ebene, KEIN tenantId/RLS — analog implementation_hints). +-- Master-Quelle für den Mandanten-Import; Versionierung (DRAFT/PUBLISHED) + Sprache (locale). + +-- CreateEnum +CREATE TYPE "PolicyTemplateStatus" AS ENUM ('DRAFT', 'PUBLISHED', 'ARCHIVED'); + +-- CreateTable +CREATE TABLE "policy_template_versions" ( + "id" TEXT NOT NULL, + "version" TEXT NOT NULL, + "status" "PolicyTemplateStatus" NOT NULL DEFAULT 'DRAFT', + "notes" TEXT, + "published_by" TEXT, + "published_at" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "policy_template_versions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_template_docs" ( + "id" TEXT NOT NULL, + "version_id" TEXT NOT NULL, + "locale" TEXT NOT NULL, + "code" TEXT NOT NULL, + "type" "PolicyDocType" NOT NULL, + "title" TEXT NOT NULL, + "doc_version" TEXT NOT NULL DEFAULT '1.0', + "policy_code" TEXT, + "fulfills" TEXT[] DEFAULT ARRAY[]::TEXT[], + "domain" "Domain", + "raw_markdown" TEXT NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "policy_template_docs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_template_requirements" ( + "id" TEXT NOT NULL, + "version_id" TEXT NOT NULL, + "locale" TEXT NOT NULL, + "req_id" TEXT NOT NULL, + "policy_code" TEXT NOT NULL, + "control" TEXT NOT NULL, + "obligation" TEXT NOT NULL, + "condition" TEXT, + "requirement" TEXT NOT NULL, + "implementation" TEXT NOT NULL, + "va_codes" TEXT[] DEFAULT ARRAY[]::TEXT[], + "nachweis_link" TEXT, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_template_requirements_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_template_variables" ( + "id" TEXT NOT NULL, + "version_id" TEXT NOT NULL, + "locale" TEXT NOT NULL, + "key" TEXT NOT NULL, + "title" TEXT NOT NULL, + "kind" TEXT NOT NULL, + "group_name" TEXT, + "value" TEXT NOT NULL, + "required" BOOLEAN NOT NULL DEFAULT false, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_template_variables_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_template_baseline_params" ( + "id" TEXT NOT NULL, + "version_id" TEXT NOT NULL, + "locale" TEXT NOT NULL, + "bl_id" TEXT NOT NULL, + "section" TEXT NOT NULL, + "name" TEXT NOT NULL, + "vorgabe" TEXT NOT NULL, + "order_idx" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_template_baseline_params_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_template_evidence" ( + "id" TEXT NOT NULL, + "version_id" TEXT NOT NULL, + "locale" TEXT NOT NULL, + "nr" INTEGER NOT NULL, + "policy_code" TEXT NOT NULL, + "nachweis" TEXT NOT NULL, + "quelle" TEXT NOT NULL, + "verantwortlich" TEXT NOT NULL, + "turnus" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_template_evidence_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_versions_version_key" ON "policy_template_versions"("version"); + +-- CreateIndex +CREATE INDEX "policy_template_versions_status_idx" ON "policy_template_versions"("status"); + +-- CreateIndex +CREATE INDEX "policy_template_docs_version_id_locale_idx" ON "policy_template_docs"("version_id", "locale"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_docs_version_id_locale_code_key" ON "policy_template_docs"("version_id", "locale", "code"); + +-- CreateIndex +CREATE INDEX "policy_template_requirements_version_id_locale_idx" ON "policy_template_requirements"("version_id", "locale"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_requirements_version_id_locale_req_id_key" ON "policy_template_requirements"("version_id", "locale", "req_id"); + +-- CreateIndex +CREATE INDEX "policy_template_variables_version_id_locale_idx" ON "policy_template_variables"("version_id", "locale"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_variables_version_id_locale_key_key" ON "policy_template_variables"("version_id", "locale", "key"); + +-- CreateIndex +CREATE INDEX "policy_template_baseline_params_version_id_locale_idx" ON "policy_template_baseline_params"("version_id", "locale"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_baseline_params_version_id_locale_bl_id_key" ON "policy_template_baseline_params"("version_id", "locale", "bl_id"); + +-- CreateIndex +CREATE INDEX "policy_template_evidence_version_id_locale_idx" ON "policy_template_evidence"("version_id", "locale"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_evidence_version_id_locale_nr_key" ON "policy_template_evidence"("version_id", "locale", "nr"); + +-- AddForeignKey +ALTER TABLE "policy_template_docs" ADD CONSTRAINT "policy_template_docs_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "policy_template_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "policy_template_requirements" ADD CONSTRAINT "policy_template_requirements_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "policy_template_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "policy_template_variables" ADD CONSTRAINT "policy_template_variables_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "policy_template_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "policy_template_baseline_params" ADD CONSTRAINT "policy_template_baseline_params_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "policy_template_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "policy_template_evidence" ADD CONSTRAINT "policy_template_evidence_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "policy_template_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260811120000_identity_foundation/migration.sql b/prisma/migrations/20260811120000_identity_foundation/migration.sql new file mode 100644 index 0000000..640e10c --- /dev/null +++ b/prisma/migrations/20260811120000_identity_foundation/migration.sql @@ -0,0 +1,54 @@ +-- ============================================================================ +-- WS0 (Option C) — Fundament: globale `Identity` + `User.identity_id` +-- ============================================================================ +-- Umbau "Zentrale Identität mit Mandanten-Mitgliedschaften" (docs/FEINDESIGN- +-- identity-mandanten.md). Dieser Schritt ist ADDITIV (Expand/Contract): +-- * `identities` wird neu angelegt und ist GLOBAL — bewusst OHNE +-- `tenant_id`, OHNE RLS/Policy und NICHT in TENANT_MODELS. Der Zugriff läuft +-- ausschließlich über den Owner-`prisma`-Client (wie heute der Login-Lookup). +-- isms_app (RLS-Rolle) greift nie direkt auf `identities` zu; die FK-Prüfung +-- beim INSERT in `users` läuft über den internen RI-Trigger (Owner-Recht) und +-- braucht kein SELECT-GRANT für isms_app. +-- * `users` behält in diesem Schritt seine Auth-Spalten (Legacy), damit Login/ +-- Guards grün und lauffähig bleiben. Die Konsumenten wandern in WS1–WS4 auf +-- Identity; die dann ungenutzten Spalten entfernt eine spätere Contract-Migration. +-- +-- Hinweis Entscheidung D: kein Backfill/Merge. `identity_id` ist NOT NULL — die +-- Migration wird deshalb auf einer LEEREN `users`-Tabelle angewandt (Test/Coolify: +-- DB leeren -> migrate deploy -> seed; lokal via `prisma migrate reset --force`). +-- ============================================================================ + +-- CreateTable (GLOBAL — keine RLS!) +CREATE TABLE "identities" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password_hash" TEXT NOT NULL, + "must_change_password" BOOLEAN NOT NULL DEFAULT false, + "mfa_secret" TEXT, + "mfa_enrolled_at" TIMESTAMP(3), + "recovery_codes" JSONB NOT NULL DEFAULT '[]', + "last_totp_step" BIGINT, + "failed_logins" INTEGER NOT NULL DEFAULT 0, + "locked_until" TIMESTAMP(3), + "sessions_valid_after" TIMESTAMP(3), + "status" TEXT NOT NULL DEFAULT 'ACTIVE', + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "identities_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "identities_email_key" ON "identities"("email"); + +-- AlterTable: Mitgliedschaft -> Identity (Option C) +ALTER TABLE "users" ADD COLUMN "identity_id" TEXT NOT NULL; + +-- CreateIndex +CREATE INDEX "users_identity_id_idx" ON "users"("identity_id"); + +-- CreateIndex: eine Person max. 1 Mitgliedschaft je Mandant +CREATE UNIQUE INDEX "users_tenant_id_identity_id_key" ON "users"("tenant_id", "identity_id"); + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_identity_id_fkey" FOREIGN KEY ("identity_id") REFERENCES "identities"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20260811140000_webauthn_identity/migration.sql b/prisma/migrations/20260811140000_webauthn_identity/migration.sql new file mode 100644 index 0000000..59d6f1f --- /dev/null +++ b/prisma/migrations/20260811140000_webauthn_identity/migration.sql @@ -0,0 +1,35 @@ +-- ============================================================================ +-- WS4b (Option C) — WebAuthn/Passkeys von der Mitgliedschaft auf die GLOBALE Identity +-- ============================================================================ +-- Passkeys sind identitäts-, nicht mandantengebunden. Die Tabelle verliert daher +-- tenant_id + RLS und verweist künftig auf `identities`. `webauthn_credentials` ist +-- damit ein GLOBALES Modell (nicht mehr in TENANT_MODELS). +-- +-- Reihenfolge: erst RLS/Policy abbauen (die Policy referenziert tenant_id), dann die +-- Spalten umbauen. identity_id ist NOT NULL — die Migration läuft auf einer leeren +-- Tabelle (im Seed werden keine Passkeys angelegt; Bestand = Testdaten). +-- ============================================================================ + +-- RLS/Policy entfernen (war über webauthn_credentials-Migration + rls_enforce gesetzt). +ALTER TABLE "webauthn_credentials" DISABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "webauthn_credentials"; + +-- DropForeignKey +ALTER TABLE "webauthn_credentials" DROP CONSTRAINT "webauthn_credentials_user_id_fkey"; + +-- DropIndex +DROP INDEX "webauthn_credentials_tenant_id_idx"; + +-- DropIndex +DROP INDEX "webauthn_credentials_user_id_idx"; + +-- AlterTable: tenant_id/user_id → identity_id +ALTER TABLE "webauthn_credentials" DROP COLUMN "tenant_id", +DROP COLUMN "user_id", +ADD COLUMN "identity_id" TEXT NOT NULL; + +-- CreateIndex +CREATE INDEX "webauthn_credentials_identity_id_idx" ON "webauthn_credentials"("identity_id"); + +-- AddForeignKey +ALTER TABLE "webauthn_credentials" ADD CONSTRAINT "webauthn_credentials_identity_id_fkey" FOREIGN KEY ("identity_id") REFERENCES "identities"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260811150000_contract_user_auth_columns/migration.sql b/prisma/migrations/20260811150000_contract_user_auth_columns/migration.sql new file mode 100644 index 0000000..6798b5d --- /dev/null +++ b/prisma/migrations/20260811150000_contract_user_auth_columns/migration.sql @@ -0,0 +1,20 @@ +-- ============================================================================ +-- Contract-Migration (Option C) — ungenutzte Auth-Spalten von `users` entfernen +-- ============================================================================ +-- Abschluss des Expand/Contract-Umbaus: Passwort/MFA/Kill-Switch/Lockout leben seit +-- WS1–WS4b ausschließlich an der GLOBALEN `Identity`. Die per-Mandant-Zeile `users` +-- ist reine Mitgliedschaft — ihre früheren (Legacy-)Auth-Spalten werden hier entfernt. +-- Nach WS1–WS4b referenziert kein Code diese Spalten mehr (durch tsc verifiziert). +-- DROP COLUMN läuft auch auf gefüllten Tabellen (kein Reset nötig). +-- ============================================================================ + +ALTER TABLE "users" DROP COLUMN "failed_logins", +DROP COLUMN "is_platform_admin", +DROP COLUMN "last_totp_step", +DROP COLUMN "locked_until", +DROP COLUMN "mfa_enrolled_at", +DROP COLUMN "mfa_secret", +DROP COLUMN "must_change_password", +DROP COLUMN "password_hash", +DROP COLUMN "recovery_codes", +DROP COLUMN "sessions_valid_after"; diff --git a/prisma/migrations/20260811160000_identity_ui_locale/migration.sql b/prisma/migrations/20260811160000_identity_ui_locale/migration.sql new file mode 100644 index 0000000..fffbca5 --- /dev/null +++ b/prisma/migrations/20260811160000_identity_ui_locale/migration.sql @@ -0,0 +1,12 @@ +-- ============================================================================ +-- Identity.uiLocale — persönliche UI-Sprache (Option C) +-- ============================================================================ +-- Neue, personengebundene Präferenz an der GLOBALEN `Identity` (folgt der Person +-- über alle Mandanten). Steuert die UI-Sprache (next-intl, src/i18n/request.ts). +-- Bewusst getrennt von `tenant_settings.locale` (= Vorlagen-Import-Sprache, Inhalt). +-- Kein RLS (Identity ist global, nicht in TENANT_MODELS). Werte: 'de' | 'en'. +-- ADD COLUMN mit Default läuft auch auf gefüllten Tabellen (kein Reset nötig). +-- ============================================================================ + +-- AlterTable +ALTER TABLE "identities" ADD COLUMN "ui_locale" TEXT NOT NULL DEFAULT 'de'; diff --git a/prisma/migrations/20260812090000_backup_dsgvo_foundation/migration.sql b/prisma/migrations/20260812090000_backup_dsgvo_foundation/migration.sql new file mode 100644 index 0000000..646751f --- /dev/null +++ b/prisma/migrations/20260812090000_backup_dsgvo_foundation/migration.sql @@ -0,0 +1,40 @@ +-- Backup/DSGVO-Lane: globale Modelle (kein tenant_id, kein RLS, analog Kataloge). + +-- CreateTable +CREATE TABLE "deletion_certificates" ( + "id" TEXT NOT NULL, + "scope" TEXT NOT NULL, + "tenant_id" TEXT, + "tenant_slug" TEXT, + "subject_identity_id" TEXT, + "subject_email" TEXT, + "actor_id" TEXT, + "deleted_counts" JSONB NOT NULL DEFAULT '{}', + "anonymized_counts" JSONB NOT NULL DEFAULT '{}', + "snapshot_id" TEXT, + "reason" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "deletion_certificates_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "tombstone_entries" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "model" TEXT NOT NULL, + "target_field" TEXT NOT NULL, + "target_value" TEXT NOT NULL, + "action" TEXT NOT NULL, + "anonymized_fields" JSONB NOT NULL DEFAULT '{}', + "reason" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "tombstone_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "deletion_certificates_tenant_id_idx" ON "deletion_certificates"("tenant_id"); +CREATE INDEX "deletion_certificates_subject_identity_id_idx" ON "deletion_certificates"("subject_identity_id"); +CREATE INDEX "tombstone_entries_tenant_id_idx" ON "tombstone_entries"("tenant_id"); +CREATE UNIQUE INDEX "tombstone_entries_tenant_id_model_target_value_key" ON "tombstone_entries"("tenant_id", "model", "target_value"); diff --git a/prisma/migrations/20260812100000_backup_jobs/migration.sql b/prisma/migrations/20260812100000_backup_jobs/migration.sql new file mode 100644 index 0000000..5c12c8b --- /dev/null +++ b/prisma/migrations/20260812100000_backup_jobs/migration.sql @@ -0,0 +1,28 @@ +-- Backup-Portal-Lane: Job-Status für Portal-Restore, Export-jetzt und DSGVO-Zustellung. +-- GLOBAL (kein tenant_id-RLS, analog deletion_certificates) — Betreiber-/Plattform-Fähigkeit. + +-- CreateTable +CREATE TABLE "backup_jobs" ( + "id" TEXT NOT NULL, + "kind" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'queued', + "tenant_id" TEXT NOT NULL, + "tenant_slug" TEXT, + "subject_identity_id" TEXT, + "actor_id" TEXT, + "snapshot_id" TEXT, + "params" JSONB NOT NULL DEFAULT '{}', + "result" JSONB, + "error" TEXT, + "download_token" TEXT, + "download_expires_at" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "backup_jobs_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "backup_jobs_download_token_key" ON "backup_jobs"("download_token"); +CREATE INDEX "backup_jobs_tenant_id_idx" ON "backup_jobs"("tenant_id"); +CREATE INDEX "backup_jobs_status_idx" ON "backup_jobs"("status"); diff --git a/prisma/migrations/20260817120000_backup_target_config/migration.sql b/prisma/migrations/20260817120000_backup_target_config/migration.sql new file mode 100644 index 0000000..5f77d1c --- /dev/null +++ b/prisma/migrations/20260817120000_backup_target_config/migration.sql @@ -0,0 +1,13 @@ +-- Lane „Konfigurierbarer Backup-Zielspeicher": PlatformSetting (Singleton) um die +-- Zielspeicher-Konfiguration erweitern. Additiv, alle Spalten nullable bzw. mit +-- Default → kein Backfill nötig, bestehende Zeile bleibt gültig (Default 'local'). +-- Das S3-Secret wird NUR verschlüsselt abgelegt (backup_s3_secret_key_enc, secret-crypto). + +ALTER TABLE "platform_settings" + ADD COLUMN "backup_target" TEXT NOT NULL DEFAULT 'local', + ADD COLUMN "backup_local_dir" TEXT, + ADD COLUMN "backup_s3_endpoint" TEXT, + ADD COLUMN "backup_s3_bucket" TEXT, + ADD COLUMN "backup_s3_region" TEXT, + ADD COLUMN "backup_s3_access_key" TEXT, + ADD COLUMN "backup_s3_secret_key_enc" TEXT; diff --git a/prisma/migrations/20260817130000_incidents/migration.sql b/prisma/migrations/20260817130000_incidents/migration.sql new file mode 100644 index 0000000..557a11c --- /dev/null +++ b/prisma/migrations/20260817130000_incidents/migration.sql @@ -0,0 +1,246 @@ +-- CreateEnum +CREATE TYPE "IncidentCategory" AS ENUM ('malware', 'phishing', 'unauthorized_access', 'data_loss', 'outage', 'physical', 'misconfiguration', 'supplier', 'prototype_customer_data', 'other'); + +-- CreateEnum +CREATE TYPE "IncidentStatus" AS ENUM ('neu', 'triage', 'in_bearbeitung', 'eingedaemmt', 'behoben', 'abgeschlossen', 'wiedereroeffnet'); + +-- AlterTable +ALTER TABLE "tenant_settings" ADD COLUMN "nis2_category" TEXT NOT NULL DEFAULT 'keine'; + +-- CreateTable +CREATE TABLE "incidents" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "ref_no" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "source" TEXT NOT NULL DEFAULT 'manual', + "reporter_name" TEXT, + "reporter_contact" TEXT, + "occurred_at" TIMESTAMP(3), + "detected_at" TIMESTAMP(3), + "reported_at" TIMESTAMP(3), + "category" "IncidentCategory" NOT NULL DEFAULT 'other', + "impact_c" INTEGER NOT NULL DEFAULT 0, + "impact_i" INTEGER NOT NULL DEFAULT 0, + "impact_a" INTEGER NOT NULL DEFAULT 0, + "urgency" INTEGER NOT NULL DEFAULT 2, + "affected_data_categories" TEXT[] DEFAULT ARRAY[]::TEXT[], + "personal_data" BOOLEAN NOT NULL DEFAULT false, + "prototype_data" BOOLEAN NOT NULL DEFAULT false, + "severity" TEXT NOT NULL DEFAULT 'mittel', + "priority" TEXT NOT NULL DEFAULT 'mittel', + "owner_id" TEXT, + "assignee_id" TEXT, + "status" "IncidentStatus" NOT NULL DEFAULT 'neu', + "restricted" BOOLEAN NOT NULL DEFAULT false, + "nis2_relevant" BOOLEAN NOT NULL DEFAULT false, + "dsgvo_relevant" BOOLEAN NOT NULL DEFAULT false, + "report_status" TEXT NOT NULL DEFAULT 'none', + "erstmeldung_due_at" TIMESTAMP(3), + "folgemeldung_due_at" TIMESTAMP(3), + "abschluss_due_at" TIMESTAMP(3), + "dsgvo_due_at" TIMESTAMP(3), + "root_cause" TEXT, + "resolution" TEXT, + "closing_note" TEXT, + "lessons_learned" TEXT, + "created_by" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "incidents_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_comments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "author_id" TEXT, + "body" TEXT NOT NULL, + "internal" BOOLEAN NOT NULL DEFAULT false, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "incident_comments_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_assets" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "asset_id" TEXT NOT NULL, + + CONSTRAINT "incident_assets_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_processes" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "process_id" TEXT NOT NULL, + + CONSTRAINT "incident_processes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_risks" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "risk_id" TEXT NOT NULL, + + CONSTRAINT "incident_risks_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_controls" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "control_ref" TEXT NOT NULL, + + CONSTRAINT "incident_controls_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_measures" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "measure_id" TEXT NOT NULL, + + CONSTRAINT "incident_measures_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "incident_attachments" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "storage_key" TEXT, + "size" INTEGER, + "mime" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "incident_attachments_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "incidents_tenant_id_idx" ON "incidents"("tenant_id"); + +-- CreateIndex +CREATE INDEX "incidents_tenant_id_status_idx" ON "incidents"("tenant_id", "status"); + +-- CreateIndex +CREATE INDEX "incidents_tenant_id_severity_idx" ON "incidents"("tenant_id", "severity"); + +-- CreateIndex +CREATE UNIQUE INDEX "incidents_tenant_id_ref_no_key" ON "incidents"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE INDEX "incident_comments_tenant_id_incident_id_idx" ON "incident_comments"("tenant_id", "incident_id"); + +-- CreateIndex +CREATE INDEX "incident_assets_tenant_id_idx" ON "incident_assets"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_assets_incident_id_asset_id_key" ON "incident_assets"("incident_id", "asset_id"); + +-- CreateIndex +CREATE INDEX "incident_processes_tenant_id_idx" ON "incident_processes"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_processes_incident_id_process_id_key" ON "incident_processes"("incident_id", "process_id"); + +-- CreateIndex +CREATE INDEX "incident_risks_tenant_id_idx" ON "incident_risks"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_risks_incident_id_risk_id_key" ON "incident_risks"("incident_id", "risk_id"); + +-- CreateIndex +CREATE INDEX "incident_controls_tenant_id_idx" ON "incident_controls"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_controls_incident_id_control_ref_key" ON "incident_controls"("incident_id", "control_ref"); + +-- CreateIndex +CREATE INDEX "incident_measures_tenant_id_idx" ON "incident_measures"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_measures_incident_id_measure_id_key" ON "incident_measures"("incident_id", "measure_id"); + +-- CreateIndex +CREATE INDEX "incident_attachments_tenant_id_incident_id_idx" ON "incident_attachments"("tenant_id", "incident_id"); + +-- AddForeignKey +ALTER TABLE "incidents" ADD CONSTRAINT "incidents_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incidents" ADD CONSTRAINT "incidents_assignee_id_fkey" FOREIGN KEY ("assignee_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_comments" ADD CONSTRAINT "incident_comments_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_assets" ADD CONSTRAINT "incident_assets_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_assets" ADD CONSTRAINT "incident_assets_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_processes" ADD CONSTRAINT "incident_processes_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_processes" ADD CONSTRAINT "incident_processes_process_id_fkey" FOREIGN KEY ("process_id") REFERENCES "processes"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_risks" ADD CONSTRAINT "incident_risks_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_risks" ADD CONSTRAINT "incident_risks_risk_id_fkey" FOREIGN KEY ("risk_id") REFERENCES "risks"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_controls" ADD CONSTRAINT "incident_controls_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_measures" ADD CONSTRAINT "incident_measures_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_measures" ADD CONSTRAINT "incident_measures_measure_id_fkey" FOREIGN KEY ("measure_id") REFERENCES "measures"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_attachments" ADD CONSTRAINT "incident_attachments_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + + +-- Row Level Security (zweite Verteidigungslinie, analog übrige Mandanten-Tabellen; +-- FORCE + WITH CHECK für den scharfen isms_app-Pfad, F-04). Lokal (Owner-Rolle ohne +-- FORCE) bleibt der Betrieb unverändert. +DO $$ +DECLARE t text; +BEGIN + FOREACH t IN ARRAY ARRAY[ + 'incidents', + 'incident_comments', + 'incident_assets', + 'incident_processes', + 'incident_risks', + 'incident_controls', + 'incident_measures', + 'incident_attachments' + ] LOOP + EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t); + EXECUTE format('DROP POLICY IF EXISTS tenant_isolation ON %I', t); + EXECUTE format( + 'CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true)) WITH CHECK (tenant_id = current_setting(''app.tenant_id'', true))', + t + ); + EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY', t); + END LOOP; +END $$; diff --git a/prisma/migrations/20260818090000_incident_links_c/migration.sql b/prisma/migrations/20260818090000_incident_links_c/migration.sql new file mode 100644 index 0000000..3368aa1 --- /dev/null +++ b/prisma/migrations/20260818090000_incident_links_c/migration.sql @@ -0,0 +1,43 @@ +-- Modul „Vorfälle" IM-C: Verknüpfung Nachweise + Abschluss-Felder (§8/§9). +-- +-- 1) incidents: Wirksamkeit der Maßnahmen + optionaler Post-Incident-Review +-- (Kurzbericht, speist das Management-Review als Feld/Notiz). +-- 2) incident_evidence: n:m-Verknüpfung Vorfall ↔ zentrales Evidence-Modell +-- (Beweissicherung, ISO A.5.28). + +-- AlterTable +ALTER TABLE "incidents" ADD COLUMN "measures_effectiveness" TEXT, +ADD COLUMN "post_incident_review" TEXT; + +-- CreateTable +CREATE TABLE "incident_evidence" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "incident_id" TEXT NOT NULL, + "evidence_id" TEXT NOT NULL, + "note" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "incident_evidence_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "incident_evidence_tenant_id_idx" ON "incident_evidence"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_evidence_incident_id_evidence_id_key" ON "incident_evidence"("incident_id", "evidence_id"); + +-- AddForeignKey +ALTER TABLE "incident_evidence" ADD CONSTRAINT "incident_evidence_incident_id_fkey" FOREIGN KEY ("incident_id") REFERENCES "incidents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "incident_evidence" ADD CONSTRAINT "incident_evidence_evidence_id_fkey" FOREIGN KEY ("evidence_id") REFERENCES "evidence"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- Row Level Security (analog übrige Mandanten-Tabellen; FORCE + WITH CHECK für den +-- scharfen isms_app-Pfad, F-04). Lokal (Owner-Rolle ohne FORCE) unverändert. +ALTER TABLE "incident_evidence" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "incident_evidence"; +CREATE POLICY tenant_isolation ON "incident_evidence" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "incident_evidence" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260818100000_incident_inbound_d/migration.sql b/prisma/migrations/20260818100000_incident_inbound_d/migration.sql new file mode 100644 index 0000000..985dfbe --- /dev/null +++ b/prisma/migrations/20260818100000_incident_inbound_d/migration.sql @@ -0,0 +1,67 @@ +-- IM-D — E-Mail-to-Ticket (Inbound) + Provisionierung. +-- 1) incidents.inbound_message_id: Idempotenz gegen Doppel-Ticket beim erneuten +-- IMAP-Abholen derselben Mail (Dedupe per Message-ID, KONZEPT §2). +-- 2) incident_intake_config: mandantengebundene Intake-Konfiguration (RLS). +-- 3) incident_inbound_review: plattformweite Review-Queue (KEINE RLS — tenant-los). + +-- AlterTable +ALTER TABLE "incidents" ADD COLUMN "inbound_message_id" TEXT; + +-- CreateIndex +CREATE INDEX "incidents_inbound_message_id_idx" ON "incidents"("inbound_message_id"); + +-- CreateTable (mandantengebunden, RLS) +CREATE TABLE "incident_intake_config" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "token" TEXT NOT NULL, + "allowlist_domains" TEXT[] DEFAULT ARRAY[]::TEXT[], + "source_address" TEXT, + "status" TEXT NOT NULL DEFAULT 'weiterleitung_ausstehend', + "verified_at" TIMESTAMP(3), + "notify_email" TEXT, + "notify_locale" TEXT NOT NULL DEFAULT 'de', + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "incident_intake_config_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_intake_config_tenant_id_key" ON "incident_intake_config"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "incident_intake_config_token_key" ON "incident_intake_config"("token"); + +-- CreateTable (plattformweit, KEINE RLS — tenant-los) +CREATE TABLE "incident_inbound_review" ( + "id" TEXT NOT NULL, + "message_id" TEXT, + "sender" TEXT NOT NULL, + "subject" TEXT, + "recipient" TEXT, + "token" TEXT, + "reason" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'offen', + "tenant_id" TEXT, + "received_at" TIMESTAMP(3) NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "incident_inbound_review_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "incident_inbound_review_status_idx" ON "incident_inbound_review"("status"); + +-- CreateIndex +CREATE INDEX "incident_inbound_review_message_id_idx" ON "incident_inbound_review"("message_id"); + +-- Row Level Security auf der mandantengebundenen Intake-Konfiguration (analog übrige +-- Mandanten-Tabellen; FORCE + WITH CHECK für den scharfen isms_app-Pfad, F-04). Die +-- Review-Queue bleibt bewusst OHNE RLS (plattformweite Betreiber-Sicht). +ALTER TABLE "incident_intake_config" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "incident_intake_config"; +CREATE POLICY tenant_isolation ON "incident_intake_config" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "incident_intake_config" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260821090000_framework_core/migration.sql b/prisma/migrations/20260821090000_framework_core/migration.sql new file mode 100644 index 0000000..f8d640d --- /dev/null +++ b/prisma/migrations/20260821090000_framework_core/migration.sql @@ -0,0 +1,67 @@ +-- CreateEnum +CREATE TYPE "Framework" AS ENUM ('ISO_27001', 'TISAX'); + +-- DropIndex +DROP INDEX "policy_package_states_tenant_id_key"; + +-- DropIndex +DROP INDEX "policy_template_versions_version_key"; + +-- AlterTable +ALTER TABLE "policy_package_states" ADD COLUMN "framework" "Framework" NOT NULL DEFAULT 'TISAX'; + +-- AlterTable +ALTER TABLE "policy_requirements" ADD COLUMN "framework" "Framework" NOT NULL DEFAULT 'TISAX'; + +-- AlterTable +ALTER TABLE "policy_template_versions" ADD COLUMN "framework" "Framework" NOT NULL DEFAULT 'TISAX'; + +-- CreateTable +CREATE TABLE "tenant_frameworks" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "framework" "Framework" NOT NULL, + "is_primary" BOOLEAN NOT NULL DEFAULT false, + "config" JSONB, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "tenant_frameworks_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "tenant_frameworks_tenant_id_idx" ON "tenant_frameworks"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "tenant_frameworks_tenant_id_framework_key" ON "tenant_frameworks"("tenant_id", "framework"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_package_states_tenant_id_framework_key" ON "policy_package_states"("tenant_id", "framework"); + +-- CreateIndex +CREATE INDEX "policy_requirements_tenant_id_framework_idx" ON "policy_requirements"("tenant_id", "framework"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_template_versions_framework_version_key" ON "policy_template_versions"("framework", "version"); + + +-- ───────────────────────────────────────────────────────────────────────────── +-- AP1 — Framework-Dimension: Backfill + RLS (manuell an das Diff-DDL angehängt). +-- ───────────────────────────────────────────────────────────────────────────── + +-- Backfill: Bestandsmandanten führen bisher TISAX → je Mandant eine TenantFramework- +-- Zeile (isPrimary=true) anlegen. Idempotent über den (tenant_id, framework)-Unique. +-- Die framework-Spalten in policy_requirements/policy_package_states/ +-- policy_template_versions sind bereits über DEFAULT 'TISAX' backfilled (s. o.). +INSERT INTO "tenant_frameworks" ("id", "tenant_id", "framework", "is_primary", "created_at") +SELECT gen_random_uuid()::text, t."id", 'TISAX', true, CURRENT_TIMESTAMP +FROM "tenants" t +ON CONFLICT ("tenant_id", "framework") DO NOTHING; + +-- Row Level Security auf der mandantengebundenen Framework-Tabelle (F-04-Muster: +-- FORCE + WITH CHECK für den scharfen isms_app-Pfad, analog übrige Mandanten-Tabellen). +ALTER TABLE "tenant_frameworks" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "tenant_frameworks"; +CREATE POLICY tenant_isolation ON "tenant_frameworks" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "tenant_frameworks" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260821100000_soa_entries/migration.sql b/prisma/migrations/20260821100000_soa_entries/migration.sql new file mode 100644 index 0000000..5f64379 --- /dev/null +++ b/prisma/migrations/20260821100000_soa_entries/migration.sql @@ -0,0 +1,37 @@ +-- CreateTable +CREATE TABLE "soa_entries" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "framework" "Framework" NOT NULL, + "control" TEXT NOT NULL, + "title" TEXT, + "applicable" BOOLEAN NOT NULL DEFAULT true, + "justification" TEXT NOT NULL DEFAULT '', + "source" TEXT, + "implementation_status" TEXT NOT NULL DEFAULT 'geplant', + "owner_id" TEXT, + "policy_code" TEXT, + "evidence_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "soa_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "soa_entries_tenant_id_idx" ON "soa_entries"("tenant_id"); + +-- CreateIndex +CREATE INDEX "soa_entries_tenant_id_framework_idx" ON "soa_entries"("tenant_id", "framework"); + +-- CreateIndex +CREATE UNIQUE INDEX "soa_entries_tenant_id_framework_control_key" ON "soa_entries"("tenant_id", "framework", "control"); + + +-- AP3 — Row Level Security auf der SoA-Tabelle (F-04: FORCE + WITH CHECK). +ALTER TABLE "soa_entries" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "soa_entries"; +CREATE POLICY tenant_isolation ON "soa_entries" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "soa_entries" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260821110000_mgmt_clauses/migration.sql b/prisma/migrations/20260821110000_mgmt_clauses/migration.sql new file mode 100644 index 0000000..4da778d --- /dev/null +++ b/prisma/migrations/20260821110000_mgmt_clauses/migration.sql @@ -0,0 +1,175 @@ +-- CreateTable +CREATE TABLE "kpis" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "data_source" TEXT, + "unit" TEXT, + "target" TEXT, + "cadence" TEXT NOT NULL DEFAULT 'monatlich', + "owner_id" TEXT, + "active" BOOLEAN NOT NULL DEFAULT true, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "kpis_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "kpi_values" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "kpi_id" TEXT NOT NULL, + "period" TEXT NOT NULL, + "value" TEXT NOT NULL, + "note" TEXT, + "recorded_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "kpi_values_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "management_reviews" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "review_date" TIMESTAMP(3) NOT NULL, + "status" TEXT NOT NULL DEFAULT 'entwurf', + "inputs" TEXT, + "results" TEXT, + "owner_id" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "management_reviews_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "management_review_decisions" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "review_id" TEXT NOT NULL, + "decision" TEXT NOT NULL, + "owner_id" TEXT, + "due_date" TIMESTAMP(3), + "status" TEXT NOT NULL DEFAULT 'offen', + + CONSTRAINT "management_review_decisions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "nonconformities" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "ref_no" TEXT NOT NULL, + "source" TEXT NOT NULL, + "description" TEXT NOT NULL, + "immediate_correction" TEXT, + "status" TEXT NOT NULL DEFAULT 'offen', + "owner_id" TEXT, + "detected_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "closed_at" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "nonconformities_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "corrective_actions" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "nonconformity_id" TEXT NOT NULL, + "root_cause" TEXT, + "action" TEXT NOT NULL, + "owner_id" TEXT, + "due_date" TIMESTAMP(3), + "status" TEXT NOT NULL DEFAULT 'geplant', + "effectiveness_check" TEXT, + "effectiveness_confirmed_at" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "corrective_actions_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "kpis_tenant_id_idx" ON "kpis"("tenant_id"); + +-- CreateIndex +CREATE INDEX "kpi_values_tenant_id_idx" ON "kpi_values"("tenant_id"); + +-- CreateIndex +CREATE INDEX "kpi_values_kpi_id_idx" ON "kpi_values"("kpi_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "kpi_values_tenant_id_kpi_id_period_key" ON "kpi_values"("tenant_id", "kpi_id", "period"); + +-- CreateIndex +CREATE INDEX "management_reviews_tenant_id_idx" ON "management_reviews"("tenant_id"); + +-- CreateIndex +CREATE INDEX "management_review_decisions_tenant_id_idx" ON "management_review_decisions"("tenant_id"); + +-- CreateIndex +CREATE INDEX "management_review_decisions_review_id_idx" ON "management_review_decisions"("review_id"); + +-- CreateIndex +CREATE INDEX "nonconformities_tenant_id_idx" ON "nonconformities"("tenant_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "nonconformities_tenant_id_ref_no_key" ON "nonconformities"("tenant_id", "ref_no"); + +-- CreateIndex +CREATE INDEX "corrective_actions_tenant_id_idx" ON "corrective_actions"("tenant_id"); + +-- CreateIndex +CREATE INDEX "corrective_actions_nonconformity_id_idx" ON "corrective_actions"("nonconformity_id"); + +-- AddForeignKey +ALTER TABLE "kpi_values" ADD CONSTRAINT "kpi_values_kpi_id_fkey" FOREIGN KEY ("kpi_id") REFERENCES "kpis"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "management_review_decisions" ADD CONSTRAINT "management_review_decisions_review_id_fkey" FOREIGN KEY ("review_id") REFERENCES "management_reviews"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "corrective_actions" ADD CONSTRAINT "corrective_actions_nonconformity_id_fkey" FOREIGN KEY ("nonconformity_id") REFERENCES "nonconformities"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- AP4 — Row Level Security (F-04: FORCE + WITH CHECK) für die neuen Mandanten-Tabellen. +ALTER TABLE "kpis" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "kpis"; +CREATE POLICY tenant_isolation ON "kpis" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "kpis" FORCE ROW LEVEL SECURITY; +ALTER TABLE "kpi_values" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "kpi_values"; +CREATE POLICY tenant_isolation ON "kpi_values" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "kpi_values" FORCE ROW LEVEL SECURITY; +ALTER TABLE "management_reviews" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "management_reviews"; +CREATE POLICY tenant_isolation ON "management_reviews" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "management_reviews" FORCE ROW LEVEL SECURITY; +ALTER TABLE "management_review_decisions" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "management_review_decisions"; +CREATE POLICY tenant_isolation ON "management_review_decisions" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "management_review_decisions" FORCE ROW LEVEL SECURITY; +ALTER TABLE "nonconformities" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "nonconformities"; +CREATE POLICY tenant_isolation ON "nonconformities" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "nonconformities" FORCE ROW LEVEL SECURITY; +ALTER TABLE "corrective_actions" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "corrective_actions"; +CREATE POLICY tenant_isolation ON "corrective_actions" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "corrective_actions" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260821120000_doc_control/migration.sql b/prisma/migrations/20260821120000_doc_control/migration.sql new file mode 100644 index 0000000..d86bdc8 --- /dev/null +++ b/prisma/migrations/20260821120000_doc_control/migration.sql @@ -0,0 +1,68 @@ +-- AlterTable +ALTER TABLE "policy_documents" ADD COLUMN "next_review_at" TIMESTAMP(3), +ADD COLUMN "review_cycle" TEXT; + +-- CreateTable +CREATE TABLE "policy_acknowledgements" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "policy_document_id" TEXT NOT NULL, + "version" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "acknowledged_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_acknowledgements_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "policy_document_versions" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "policy_document_id" TEXT NOT NULL, + "version" TEXT NOT NULL, + "title" TEXT NOT NULL, + "change_note" TEXT, + "created_by" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "policy_document_versions_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "policy_acknowledgements_tenant_id_idx" ON "policy_acknowledgements"("tenant_id"); + +-- CreateIndex +CREATE INDEX "policy_acknowledgements_policy_document_id_version_idx" ON "policy_acknowledgements"("policy_document_id", "version"); + +-- CreateIndex +CREATE UNIQUE INDEX "policy_acknowledgements_tenant_id_policy_document_id_user_i_key" ON "policy_acknowledgements"("tenant_id", "policy_document_id", "user_id", "version"); + +-- CreateIndex +CREATE INDEX "policy_document_versions_tenant_id_idx" ON "policy_document_versions"("tenant_id"); + +-- CreateIndex +CREATE INDEX "policy_document_versions_policy_document_id_idx" ON "policy_document_versions"("policy_document_id"); + +-- CreateIndex +CREATE INDEX "policy_documents_tenant_id_next_review_at_idx" ON "policy_documents"("tenant_id", "next_review_at"); + +-- AddForeignKey +ALTER TABLE "policy_acknowledgements" ADD CONSTRAINT "policy_acknowledgements_policy_document_id_fkey" FOREIGN KEY ("policy_document_id") REFERENCES "policy_documents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "policy_document_versions" ADD CONSTRAINT "policy_document_versions_policy_document_id_fkey" FOREIGN KEY ("policy_document_id") REFERENCES "policy_documents"("id") ON DELETE CASCADE ON UPDATE CASCADE; + + +-- AP5 — Row Level Security (F-04) für die neuen Mandanten-Tabellen. +ALTER TABLE "policy_acknowledgements" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_acknowledgements"; +CREATE POLICY tenant_isolation ON "policy_acknowledgements" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_acknowledgements" FORCE ROW LEVEL SECURITY; +ALTER TABLE "policy_document_versions" ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS tenant_isolation ON "policy_document_versions"; +CREATE POLICY tenant_isolation ON "policy_document_versions" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "policy_document_versions" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/20260907084110_add_process_dependencies/migration.sql b/prisma/migrations/20260907084110_add_process_dependencies/migration.sql new file mode 100644 index 0000000..df132d0 --- /dev/null +++ b/prisma/migrations/20260907084110_add_process_dependencies/migration.sql @@ -0,0 +1,35 @@ +-- CreateTable +CREATE TABLE "process_dependencies" ( + "id" TEXT NOT NULL, + "tenant_id" TEXT NOT NULL, + "source_process_id" TEXT NOT NULL, + "target_process_id" TEXT NOT NULL, + "note" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "process_dependencies_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "process_dependencies_tenant_id_idx" ON "process_dependencies"("tenant_id"); + +-- CreateIndex +CREATE INDEX "process_dependencies_target_process_id_idx" ON "process_dependencies"("target_process_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "process_dependencies_source_process_id_target_process_id_key" ON "process_dependencies"("source_process_id", "target_process_id"); + +-- AddForeignKey +ALTER TABLE "process_dependencies" ADD CONSTRAINT "process_dependencies_source_process_id_fkey" FOREIGN KEY ("source_process_id") REFERENCES "processes"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "process_dependencies" ADD CONSTRAINT "process_dependencies_target_process_id_fkey" FOREIGN KEY ("target_process_id") REFERENCES "processes"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- Row Level Security: Mandantentrennung (analog übrige tenant-scoped Tabellen) +ALTER TABLE "process_dependencies" ENABLE ROW LEVEL SECURITY; + +CREATE POLICY tenant_isolation ON "process_dependencies" + USING ("tenant_id" = current_setting('app.tenant_id', true)) + WITH CHECK ("tenant_id" = current_setting('app.tenant_id', true)); +ALTER TABLE "process_dependencies" FORCE ROW LEVEL SECURITY; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..a5e8f7d --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,2522 @@ +// ISMS-Tool — Prisma-Schema +// Fundament (Iteration 1): Mandanten, Nutzer, RBAC, Audit-Log. +// Fachliche Entitäten (Assets, BIA, Risiken, …) folgen je Iteration — siehe docs/SPEC.md §5. +// +// Multi-Tenant-Regel: Jede fachliche Tabelle trägt tenantId. Zugriff nur über den +// zentralen Tenant-Guard (src/server/db.ts); zusätzlich Postgres RLS (prisma/rls.sql). + +generator client { + provider = "prisma-client-js" + previewFeatures = ["postgresqlExtensions"] +} + +datasource db { + provider = "postgresql" + extensions = [pgvector(map: "vector")] +} + +enum TenantStatus { + ACTIVE + SUSPENDED + ARCHIVED +} + +enum UserStatus { + ACTIVE + INVITED + LOCKED + DEACTIVATED +} + +model Tenant { + id String @id @default(cuid()) + name String + slug String @unique + short String? + sector String? + status TenantStatus @default(ACTIVE) + config Json @default("{}") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + users User[] + roles Role[] + auditLogs AuditLog[] + settings TenantSettings? + modules TenantModule[] + + @@map("tenants") +} + +// Mandanten-Einstellungen: Quelle der ISMS-Template-Variablen (§4.1) + Branding/Policy +model TenantSettings { + id String @id @default(cuid()) + tenantId String @unique @map("tenant_id") + orgName String @map("org_name") + orgShort String? @map("org_short") + address String? + sector String? + duns String? + ismsScope String? @map("isms_scope") + ismsScopeDescription String? @map("isms_scope_description") + roleManagement String? @map("role_management") + roleIsb String? @map("role_isb") + roleItLead String? @map("role_it_lead") + roleDpo String? @map("role_dpo") + logoKey String? @map("logo_key") + accent String? + locale String @default("de") + timezone String @default("Europe/Berlin") + tisaxLevel String @default("AL2") @map("tisax_level") // AL2 | AL3 + // NIS2-Betroffenheit des Mandanten (steuert später die Meldefristen-Timer, IM-B). + // keine | wichtig | wesentlich. Default "keine". + nis2Category String @default("keine") @map("nis2_category") + securityPolicy Json @default("{}") @map("security_policy") // pw/mfa/session + smtp Json @default("{}") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("tenant_settings") +} + +// Modul-Freischaltung je Mandant (Feature-Toggle) — gated Navigation, API und Daten +model TenantModule { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + moduleKey String @map("module_key") + enabled Boolean @default(true) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) + + @@unique([tenantId, moduleKey]) + @@index([tenantId]) + @@map("tenant_modules") +} + +// Zentrale, GLOBALE Anmelde-Identität einer Person (Option C — Umbau +// "Identity + Mandanten-Mitgliedschaften"). E-Mail/Passwort/MFA leben hier; +// die per-Mandant-Zeile `User` ist künftig die "Mitgliedschaft" und verweist per +// identityId hierher. WICHTIG (Goldene Regeln WS0): +// - Identity ist GLOBAL: KEIN tenant_id, NICHT in TENANT_MODELS, KEINE RLS-Policy. +// Lookup läuft über den Owner-`prisma`-Client (wie heute der Login). +// Expand/Contract: In diesem WS0-Schritt (additiv) trägt `User` seine Auth-Felder +// noch parallel (Legacy), damit der bestehende Login/Guards grün bleiben. Die +// Konsumenten wandern in WS1–WS4 auf Identity; die dann ungenutzten User-Spalten +// entfernt eine spätere Contract-Migration. +model Identity { + id String @id @default(cuid()) + email String @unique + passwordHash String @map("password_hash") + // Erzwungener Passwortwechsel beim nächsten Login (Initial-/Reset-Passwort). + mustChangePassword Boolean @default(false) @map("must_change_password") + // Optionale TOTP-MFA der Identity. recoveryCodes = Argon2id-Hashes (F-17). + mfaSecret String? @map("mfa_secret") + mfaEnrolledAt DateTime? @map("mfa_enrolled_at") + recoveryCodes Json @default("[]") @map("recovery_codes") + // F-17: zuletzt akzeptierter TOTP-Zeitschritt (RFC 6238) — Replay-Schutz. + lastTotpStep BigInt? @map("last_totp_step") + // Brute-Force-Schutz Login (F-05): Fehlversuchszähler + Sperre bis. + failedLogins Int @default(0) @map("failed_logins") + lockedUntil DateTime? @map("locked_until") + // SEC2: globaler Session-Kill-Switch (siehe User.sessionsValidAfter). Ein Token, + // dessen `iat` davor liegt, gilt als ungültig. + sessionsValidAfter DateTime? @map("sessions_valid_after") + status String @default("ACTIVE") // ACTIVE | LOCKED | DISABLED + // Persönliche UI-Sprache der Person (Option C, folgt der Identity über alle + // Mandanten). Getrennt von TenantSettings.locale (= Vorlagen-Import-Sprache). + uiLocale String @default("de") @map("ui_locale") // de | en + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + memberships User[] + // WS4b: Passkeys sind identitäts-, nicht mandantengebunden. + webauthnCredentials WebAuthnCredential[] + + @@map("identities") +} + +model User { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + // Verweis auf die globale Anmelde-Identität (Option C). Quelle für Auth ist + // künftig Identity; `email` bleibt hier als Denormalisierung (Anzeige/Filter, + // Bestands-Upsert-Key tenantId_email). + // Verweis auf die globale Anmelde-Identität (Option C). Auth (Passwort/MFA/Kill- + // Switch/Lockout) lebt ausschließlich an der Identity — die früheren Auth-Spalten + // wurden mit der Contract-Migration entfernt (Expand/Contract abgeschlossen). + identityId String @map("identity_id") + email String // Denormalisierung (Anzeige/Filter, Upsert-Key tenantId_email) + name String + status UserStatus @default(ACTIVE) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + tenant Tenant @relation(fields: [tenantId], references: [id]) + identity Identity @relation(fields: [identityId], references: [id]) + userRoles UserRole[] + ownedAssets Asset[] @relation("assetOwner") + ownedProcesses Process[] @relation("processOwner") + ownedRisks Risk[] @relation("riskOwner") + ownedMeasures Measure[] @relation("measureOwner") + ownedIncidents Incident[] @relation("incidentOwner") + assignedIncidents Incident[] @relation("incidentAssignee") + + @@unique([tenantId, email]) + // Option C: eine Person (Identity) hat je Mandant höchstens EINE Mitgliedschaft. + @@unique([tenantId, identityId]) + @@index([tenantId]) + @@index([identityId]) + @@map("users") +} + +// SEC3-b / WS4b: WebAuthn/Passkey-Credential einer GLOBALEN Identity (2. Faktor, +// Alternative zu TOTP). Passkeys sind identitäts-, nicht mandantengebunden → KEIN +// tenant_id, NICHT in TENANT_MODELS, keine RLS. credentialId/publicKey base64url. +model WebAuthnCredential { + id String @id @default(cuid()) + identityId String @map("identity_id") + credentialId String @unique @map("credential_id") // base64url der Credential-ID + publicKey String @map("public_key") // base64url der COSE-Public-Key-Bytes + counter BigInt @default(0) + transports String[] @default([]) + deviceName String? @map("device_name") + createdAt DateTime @default(now()) @map("created_at") + lastUsedAt DateTime? @map("last_used_at") + + identity Identity @relation(fields: [identityId], references: [id], onDelete: Cascade) + + @@index([identityId]) + @@map("webauthn_credentials") +} + +model Role { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + key String // z. B. tenant-admin, isb, auditor, owner, user + name String + + tenant Tenant @relation(fields: [tenantId], references: [id]) + userRoles UserRole[] + rolePermissions RolePermission[] + + @@unique([tenantId, key]) + @@index([tenantId]) + @@map("roles") +} + +model Permission { + id String @id @default(cuid()) + key String @unique // z. B. asset:read, risk:write, incident:manage + + rolePermissions RolePermission[] + + @@map("permissions") +} + +model UserRole { + userId String @map("user_id") + roleId String @map("role_id") + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) + + @@id([userId, roleId]) + @@map("user_roles") +} + +model RolePermission { + roleId String @map("role_id") + permissionId String @map("permission_id") + + role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) + permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) + + @@id([roleId, permissionId]) + @@map("role_permissions") +} + +// Plattform-Administratoren (Betreiber). Getrennter Store OHNE tenant_id, eigener +// Login (/platform/login), TOTP-MFA-Pflicht + Recovery-Codes. Kein Zugriff auf +// Mandanten-Fachdaten (nur Betrieb: Mandanten, Module, Lebenszyklus). §Phase-1-Härtung. +model PlatformAdmin { + id String @id @default(cuid()) + email String @unique + passwordHash String @map("password_hash") + name String + status String @default("ACTIVE") // ACTIVE | LOCKED | DISABLED + // SEC4: Plattform-Rolle. "full" = Voll-Admin (darf verwalten), "readonly" = nur lesen. + role String @default("full") @map("role") // full | readonly + mfaSecret String? @map("mfa_secret") + mfaEnrolledAt DateTime? @map("mfa_enrolled_at") + recoveryCodes Json @default("[]") @map("recovery_codes") // Argon2id-Hashes der Recovery-Codes (F-17; Alt: SHA-256, übergangsweise akzeptiert) + failedLogins Int @default(0) @map("failed_logins") + lockedUntil DateTime? @map("locked_until") + // F-17: zuletzt akzeptierter TOTP-Zeitschritt (RFC 6238) — Replay-Schutz. + lastTotpStep BigInt? @map("last_totp_step") + lastLoginAt DateTime? @map("last_login_at") + // SEC2: siehe User.sessionsValidAfter — gleiche Semantik für die getrennte + // Plattform-Auth-Domäne. + sessionsValidAfter DateTime? @map("sessions_valid_after") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@map("platform_admins") +} + +// Plattformweite Betriebseinstellungen (Singleton). Steuert u. a., ob MFA für +// Plattform-Admins verpflichtend ist (Default: aus → MFA optional, Paket C). +model PlatformSetting { + id String @id @default("singleton") + mfaRequired Boolean @default(false) @map("mfa_required") + + // Backup-Zielspeicher (Lane „Konfigurierbarer Backup-Zielspeicher"). Additiv, + // nullable, Default `local` → bestehende Deployments laufen unverändert über Env. + // Präzedenz zur Laufzeit: DB-Config (diese Felder) → Env (S3_*/BACKUP_LOCAL_DIR) + // → lokaler Default `.backups`. Das S3-Secret liegt NUR verschlüsselt (secret-crypto). + backupTarget String @default("local") @map("backup_target") // local | s3 + backupLocalDir String? @map("backup_local_dir") + backupS3Endpoint String? @map("backup_s3_endpoint") + backupS3Bucket String? @map("backup_s3_bucket") + backupS3Region String? @map("backup_s3_region") + backupS3AccessKey String? @map("backup_s3_access_key") + backupS3SecretKeyEnc String? @map("backup_s3_secret_key_enc") // secret-crypto, nie Klartext + + updatedAt DateTime @updatedAt @map("updated_at") + + @@map("platform_settings") +} + +// ── Assets & BIA (ein Modul, SPEC §4.1) ───────────────────────────────────── + +enum AssetType { + INFORMATION + SYSTEM + APPLICATION + LOCATION + SUPPLIER + IT_SERVICE + SOFTWARE + PROJECT + PERSON + DATA +} + +enum AssetStatus { + ACTIVE + PLANNED + RETIRED +} + +enum ProcessAssetRole { + PRIMARY + SECONDARY +} + +enum ProcessCategory { + CORE // Kernprozess + MANAGEMENT // Managementprozess + SUPPORT // Unterstützender Prozess +} + +model Asset { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String + description String? + type AssetType + status AssetStatus @default(ACTIVE) + ownerId String? @map("owner_id") + location String? + tags String[] @default([]) + // Schutzbedarf 1–4 je Schutzziel (C/I/A) + confidentiality Int @default(1) + integrity Int @default(1) + availability Int @default(1) + // M2 Strukturanalyse: Dedup-/Autocomplete-Schlüssel (s. src/lib/normalize-asset.ts). + // Normalisierter Name (trim → Whitespace kollabieren → NFC → lowercase(de) → + // Umlaut-Faltung → Satzzeichen entfernt). Exakt-Duplikate je Mandant verhindert + // die @@unique unten → bei Treffer wird verknüpft statt neu angelegt. + normalizedName String? @map("normalized_name") + // Schutz-/Klassifizierungslabel (primäres Informations-Asset): steuert Scope/Bereiche. + label InfoLabel @default(NONE) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + owner User? @relation("assetOwner", fields: [ownerId], references: [id]) + relationsFrom AssetRelation[] @relation("relationFrom") + relationsTo AssetRelation[] @relation("relationTo") + processAssets ProcessAsset[] + riskAssets RiskAsset[] + incidentAssets IncidentAsset[] + + // Lieferanten-/IT-Service-Erweiterungen (1:1) + Kind-Entitäten + supplierProfile SupplierProfile? + serviceProfile ITServiceProfile? @relation("serviceAsset") + serviceProvided ITServiceProfile[] @relation("serviceProvider") + softwareProfile SoftwareProfile? @relation("softwareAsset") + softwareProvided SoftwareProfile[] @relation("softwareProvider") + projectProfile ProjectProfile? + assessments SupplierAssessment[] + evidence SupplierEvidence[] + decisions ManagementDecision[] + contracts Contract[] + ndas Nda[] + subcontractors Subcontractor[] + raci ServiceControlResponsibility[] + maturity MaturityAssessment? + + @@unique([tenantId, normalizedName]) + @@index([tenantId]) + @@index([tenantId, type]) + @@map("assets") +} + +// M2 Strukturanalyse (Ebene 2): Standard-Prozess-Katalog. GLOBALER Katalog-Content +// (identisch je Mandant) → kein tenantId/RLS, analog RiskCatalogEntry. Kuratierte +// Vorauswahl typischer Kern-/Management-/Unterstützungsprozesse mit Vorschlägen für +// Träger-Asset-Typen, Standard-Risiken (→ RiskCatalogEntry.code) und Info-Labels. +// Wird im prozessgeführten Wizard-Schritt angeboten und ins mandanteneigene +// Process-Register übernommen (dort anpassbar). +model ProcessCatalogEntry { + id String @id @default(cuid()) + code String @unique + name String + category ProcessCategory // CORE | MANAGEMENT | SUPPORT ("Neben"→SUPPORT) + parentCode String? @map("parent_code") // Katalog-Prozess-Tiefe: Teilprozess von <code> + suggestedAssetTypes AssetType[] @map("suggested_asset_types") + suggestedRiskCodes String[] @default([]) @map("suggested_risk_codes") // → RiskCatalogEntry.code + suggestedInfoLabels InfoLabel[] @map("suggested_info_labels") + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + @@map("process_catalog") +} + +model AssetRelation { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") + relatedAssetId String @map("related_asset_id") + // z. B. depends_on, hosts, processes_data_of + type String @default("depends_on") + + asset Asset @relation("relationFrom", fields: [assetId], references: [id], onDelete: Cascade) + relatedAsset Asset @relation("relationTo", fields: [relatedAssetId], references: [id], onDelete: Cascade) + + @@unique([assetId, relatedAssetId, type]) + @@index([tenantId]) + @@map("asset_relations") +} + +model Process { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String + description String? + category ProcessCategory @default(CORE) + ownerId String? @map("owner_id") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + // TISAX v3 — mehr fachliche Prozess-Informationen (additiv). + purpose String? @map("purpose") // Zweck / Ziel des Prozesses + parentId String? @map("parent_id") // Haupt-/Teilprozess-Hierarchie (Prozesshaus-Tiefe) + deputyOwnerId String? @map("deputy_owner_id") // Stellvertreter (User-Id, in App aufgelöst) + catalogCode String? @map("catalog_code") // Herkunft aus ProcessCatalogEntry (behebt Namens-Matching) + inScope Boolean @default(true) @map("in_scope") // Prozesshaus-Aktivierung + dataProtectionRelevant Boolean @default(false) @map("data_protection_relevant") + prototypeRelevant Boolean @default(false) @map("prototype_relevant") + legalBasis String? @map("legal_basis") // gesetzliche/vertragliche Grundlage + interfaces String? @map("interfaces") // Schnittstellen / Datenflüsse + biaStatus String @default("offen") @map("bia_status") // offen | teilweise | komplett (Prozesshaus-Farbe) + + owner User? @relation("processOwner", fields: [ownerId], references: [id]) + parent Process? @relation("processHierarchy", fields: [parentId], references: [id]) + children Process[] @relation("processHierarchy") + processAssets ProcessAsset[] + bia BiaEntry? + risks Risk[] + incidentProcesses IncidentProcess[] + // Strukturierte Prozess-zu-Prozess-Abhängigkeiten (source „benötigt" target). + dependsOn ProcessDependency[] @relation("processDependsOn") + requiredBy ProcessDependency[] @relation("processRequiredBy") + + @@index([tenantId]) + @@index([tenantId, parentId]) + @@map("processes") +} + +/// Strukturierte Abhängigkeit zwischen zwei Prozessen desselben Mandanten: `source` +/// benötigt `target` (z. B. „Produktentwicklung" benötigt „IT-Betrieb"). Erlaubt die +/// Rückrichtung („wird benötigt von") und Auswertungen wie „N Prozesse hängen an X". +/// Mandantengebunden (RLS). Löschen eines Prozesses entfernt seine Kanten (Cascade). +model ProcessDependency { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + sourceProcessId String @map("source_process_id") + targetProcessId String @map("target_process_id") + note String? + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + source Process @relation("processDependsOn", fields: [sourceProcessId], references: [id], onDelete: Cascade) + target Process @relation("processRequiredBy", fields: [targetProcessId], references: [id], onDelete: Cascade) + + @@unique([sourceProcessId, targetProcessId]) + @@index([tenantId]) + @@index([targetProcessId]) + @@map("process_dependencies") +} + +model ProcessAsset { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + processId String @map("process_id") + assetId String @map("asset_id") + role ProcessAssetRole @default(SECONDARY) + + process Process @relation(fields: [processId], references: [id], onDelete: Cascade) + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@unique([processId, assetId]) + @@index([tenantId]) + @@map("process_assets") +} + +model BiaEntry { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + processId String @unique @map("process_id") + // Wiederanlaufparameter in Stunden (SPEC §4.1.2) + rtoHours Int? @map("rto_hours") + rpoHours Int? @map("rpo_hours") + mtdHours Int? @map("mtd_hours") + // Schadenshöhe 1–4 je Schutzziel + impactC Int @default(1) @map("impact_c") + impactI Int @default(1) @map("impact_i") + impactA Int @default(1) @map("impact_a") + // Kritikalität 1–4, abgeleitet (Max-Prinzip), redundant gespeichert für Listen/Filter + criticality Int @default(1) + notes String? + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + process Process @relation(fields: [processId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("bia_entries") +} + +// ── Risikoanalyse (SPEC §4.2) ─────────────────────────────────────────────── + +enum RiskTreatment { + AVOID // Vermeiden + MITIGATE // Vermindern + TRANSFER // Übertragen + ACCEPT // Akzeptieren +} + +enum RiskStatus { + OPEN + IN_TREATMENT + ACCEPTED + CLOSED +} + +model Risk { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + // Laufende Nummer je Mandant → Anzeige als "R-001" + refNo Int @map("ref_no") + + title String + description String? + threat String? // Bedrohung (Katalog folgt, SPEC §5) + vulnerability String? // Schwachstelle + catalogCode String? @map("catalog_code") // Herkunft aus dem Standard-Risikokatalog (Story A6, R-<KAT>-<nr>) + + // Brutto-Bewertung: Eintrittswahrscheinlichkeit × Auswirkung (je 1–5) + likelihood Int @default(1) + impact Int @default(1) + score Int @default(1) // redundant für Listen/Heatmap + + // Rest-Risiko nach Maßnahmen (berechnet, dezimal wegen Teil-Minderungen) + residualLikelihood Float? @map("residual_likelihood") + residualImpact Float? @map("residual_impact") + residualScore Float? @map("residual_score") + + treatment RiskTreatment @default(MITIGATE) + status RiskStatus @default(OPEN) + ownerId String? @map("owner_id") + processId String? @map("process_id") + // Dokumentierte Risikoakzeptanz (VA-09, Story A6-2) — Pflicht bei Restrisiko über Schwelle + acceptanceRationale String? @map("acceptance_rationale") + acceptedById String? @map("accepted_by_id") + acceptedAt DateTime? @map("accepted_at") + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + owner User? @relation("riskOwner", fields: [ownerId], references: [id]) + process Process? @relation(fields: [processId], references: [id]) + riskAssets RiskAsset[] + riskMeasures RiskMeasure[] + incidentRisks IncidentRisk[] + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@index([tenantId, status]) + @@map("risks") +} + +// Standard-Risikokatalog (Story A6-1, Fachcontent C4). GLOBALER Katalog-Content +// (identisch je Mandant) → kein tenantId/RLS. Kuratierte Vorauswahl typischer +// IS-/TISAX-Risiken mit Default-Bewertung (E×S, 5×5), Controls, Asset-Typen und +// Standardmaßnahme. Wird im Wizard/Risikomodul angeboten und ins mandanteneigene +// Risk-Register übernommen (dort anpassbar). +model RiskCatalogEntry { + id String @id @default(cuid()) + code String @unique // R-ORG-01 + category String // ORG | HR | PHY | IAM | CRY | OPS | NET | SUP | DEV | PROTO | DSGVO + title String + description String + controls String[] @default([]) // ISA-Control-Refs + assetTypes String[] @default([]) @map("asset_types") + standardMeasure String @map("standard_measure") + defaultLikelihood Int @map("default_likelihood") // E (1–5) + defaultImpact Int @map("default_impact") // S (1–5) + rationale String + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + @@index([category]) + @@map("risk_catalog_entries") +} + +model RiskAsset { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + riskId String @map("risk_id") + assetId String @map("asset_id") + + risk Risk @relation(fields: [riskId], references: [id], onDelete: Cascade) + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@unique([riskId, assetId]) + @@index([tenantId]) + @@map("risk_assets") +} + +// ── Maßnahmen (SPEC §4.4) ─────────────────────────────────────────────────── + +enum MeasureStatus { + OPEN + IN_PROGRESS + DONE +} + +enum MeasurePriority { + LOW + MEDIUM + HIGH +} + +model Measure { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + refNo Int @map("ref_no") // Anzeige als "M-001" + + title String + description String? + status MeasureStatus @default(OPEN) + priority MeasurePriority @default(MEDIUM) + ownerId String? @map("owner_id") + dueDate DateTime? @map("due_date") + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + owner User? @relation("measureOwner", fields: [ownerId], references: [id]) + riskMeasures RiskMeasure[] + incidentMeasures IncidentMeasure[] + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@index([tenantId, status]) + @@map("measures") +} + +// Verknüpfung Risiko ↔ Maßnahme inkl. erwarteter Risikominderung: +// Das Rest-Risiko wird aus likelihood/impact minus der Summe der +// Minderungen aller verknüpften Maßnahmen berechnet (siehe src/server/risk-calc.ts). +model RiskMeasure { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + riskId String @map("risk_id") + measureId String @map("measure_id") + + // Minderung je Dimension (0,00–4,00) — mehrere Maßnahmen summieren sich, + // bis ein voller Punkt (oder mehr) erreicht ist + reductionLikelihood Float @default(0) @map("reduction_likelihood") + reductionImpact Float @default(0) @map("reduction_impact") + + risk Risk @relation(fields: [riskId], references: [id], onDelete: Cascade) + measure Measure @relation(fields: [measureId], references: [id], onDelete: Cascade) + + @@unique([riskId, measureId]) + @@index([tenantId]) + @@map("risk_measures") +} + +// Globale Kataloge (SPEC §5: Threat/Vulnerability, mandantenübergreifend). +// Risiken speichern weiterhin Freitext — der Katalog liefert Vorschläge (datalist), +// eigene Formulierungen bleiben möglich. +model Threat { + id String @id @default(cuid()) + name String @unique + + @@map("threats") +} + +model Vulnerability { + id String @id @default(cuid()) + name String @unique + + @@map("vulnerabilities") +} + +// ── Lieferanten- & IT-Service-Management (VDA-ISA 2027 Kap. 6, NIS2 Art. 21(2)(d)) ── +// Grundsatz: Lieferanten UND IT-Services sind Assets (type SUPPLIER | IT_SERVICE). +// SupplierProfile/ITServiceProfile sind 1:1-Erweiterungen eines Asset; alle +// Kind-Entitäten hängen am Asset (subject) — keine parallele Datenhaltung. + +enum SupplierLifecycle { + ACTIVE + ONBOARDING + UNDER_REVIEW + OFFBOARDED +} + +enum AssessmentType { + QUESTIONNAIRE + SELF_ASSESSMENT + AUDIT +} + +enum EvidenceKind { + CERTIFICATE + TISAX_LABEL + ATTESTATION + AUDIT_REPORT + SELF_ASSESSMENT +} + +enum RaciResponsibility { + PROVIDER + US + SHARED +} + +model SupplierProfile { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @unique @map("asset_id") + refNo Int @map("ref_no") + + sector String? + serviceDesc String? @map("service_desc") + criticality Int @default(1) + dataCategories String[] @default([]) @map("data_categories") + nis2Relevant Boolean @default(false) @map("nis2_relevant") + lifecycle SupplierLifecycle @default(ACTIVE) + contact String? + tisaxLabel String? @map("tisax_label") + tisaxValidTo DateTime? @map("tisax_valid_to") + nextReview DateTime? @map("next_review") + notes String? + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@map("supplier_profiles") +} + +model ITServiceProfile { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @unique @map("asset_id") + refNo Int @map("ref_no") + providerAssetId String? @map("provider_asset_id") // Asset(type SUPPLIER) + criticality Int @default(1) + internal Boolean @default(false) + notes String? + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + asset Asset @relation("serviceAsset", fields: [assetId], references: [id], onDelete: Cascade) + provider Asset? @relation("serviceProvider", fields: [providerAssetId], references: [id]) + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@map("it_service_profiles") +} + +// Software-Whitelist als Asset (analog IT-Service, R11/VA-16): eine freigegebene +// Software ist ein Asset(type SOFTWARE) mit optionalem Anbieter (Asset type SUPPLIER). +model SoftwareProfile { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @unique @map("asset_id") + refNo Int @map("ref_no") + providerAssetId String? @map("provider_asset_id") // Asset(type SUPPLIER) + version String? // Version/Patch-Stand + approvalStatus SoftwareApprovalStatus @default(BEANTRAGT) @map("approval_status") + approvedBy String? @map("approved_by") + criticality Int @default(1) + nextReview DateTime? @map("next_review") + notes String? + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + asset Asset @relation("softwareAsset", fields: [assetId], references: [id], onDelete: Cascade) + provider Asset? @relation("softwareProvider", fields: [providerAssetId], references: [id]) + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@map("software_profiles") +} + +enum SoftwareApprovalStatus { + BEANTRAGT // Freigabe beantragt + FREIGEGEBEN // freigegeben (Whitelist) + GESPERRT // gesperrt/untersagt +} + +// Informationssicherheit in Projekten (R01/VA-19): ein Projekt ist ein Asset(type PROJECT) +// mit Kritikalität (C/I/A am Asset) und Risiko-Verknüpfung (RiskAsset). +model ProjectProfile { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @unique @map("asset_id") + refNo Int @map("ref_no") + classification String? // IS-Klassifizierung + isbInvolved Boolean @default(false) @map("isb_involved") + status ProjectStatus @default(GEPLANT) + notes String? + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + createdBy String? @map("created_by") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@map("project_profiles") +} + +enum ProjectStatus { + GEPLANT + LAUFEND + ABGESCHLOSSEN + ABGEBROCHEN +} + +// Bewertung & Nachweise (6.1.1) +model SupplierAssessment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") + type AssessmentType + score Int? + selfScore Int? @map("self_score") + verifiedScore Int? @map("verified_score") + date DateTime? + nextReview DateTime? @map("next_review") + result String? + createdAt DateTime @default(now()) @map("created_at") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("supplier_assessments") +} + +model SupplierEvidence { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") // Subjekt (Lieferant ODER Service) + kind EvidenceKind + name String? + protectsCia String? @map("protects_cia") + validTo DateTime? @map("valid_to") + adequacyChecked Boolean @default(false) @map("adequacy_checked") + createdAt DateTime @default(now()) @map("created_at") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("supplier_evidence") +} + +model ManagementDecision { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") + reasonNoAudit String @map("reason_no_audit") + decision String + decidedBy String? @map("decided_by") + date DateTime @default(now()) + recordRef String? @map("record_ref") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("management_decisions") +} + +// Vertrag & Geheimhaltung (6.1.1 / 6.1.2) +model Contract { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") + type String @default("service") + avDpa Boolean @default(false) @map("av_dpa") + securityClauses Boolean @default(false) @map("security_clauses") + flowdown Boolean @default(false) + customerRequirementsPassed Boolean @default(false) @map("customer_requirements_passed") + validFrom DateTime? @map("valid_from") + validTo DateTime? @map("valid_to") + reference String? + createdAt DateTime @default(now()) @map("created_at") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("contracts") +} + +model Nda { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") + parties String? + infoScope String? @map("info_scope") + subject String? + validFrom DateTime? @map("valid_from") + validTo DateTime? @map("valid_to") + obligations String? + beyondTerm Boolean @default(false) @map("beyond_term") + extensionStatus String? @map("extension_status") + createdAt DateTime @default(now()) @map("created_at") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("ndas") +} + +model Subcontractor { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") + name String + flowdownObligation Boolean @default(false) @map("flowdown_obligation") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("subcontractors") +} + +// Verantwortung je IT-Service (6.1.3) — RACI über den ISA-Control-Katalog +model ServiceControlResponsibility { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @map("asset_id") // Asset(type IT_SERVICE) + controlRef String @map("control_ref") + title String? + applicable Boolean @default(true) + responsibility RaciResponsibility @default(SHARED) + evidenceRef String? @map("evidence_ref") + createdAt DateTime @default(now()) @map("created_at") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("service_control_responsibilities") +} + +// Reifegrad je Subjekt — Fragebogen-Selbstauskunft, durch Nachweise verifiziert, ISB-Freigabe +model MaturityAssessment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + assetId String @unique @map("asset_id") + selfValue Float? @map("self_value") + verifiedValue Float? @map("verified_value") + computedValue Float? @map("computed_value") + isbValue Float? @map("isb_value") + isbJustification String? @map("isb_justification") + approvedBy String? @map("approved_by") + approvedAt DateTime? @map("approved_at") + updatedAt DateTime @updatedAt @map("updated_at") + + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@map("maturity_assessments") +} + +// Control-Assessment (Story A7-2): bestätigter/überschriebener Reifegrad je Control +// (VDA-ISA 0–3) aus dem Onboarding-Schritt 7. Der Vorschlag (`suggested`) wird regelbasiert +// aus dem Belegstand hergeleitet (src/lib/maturity.ts); `confirmedValue` ist die Pflicht- +// bestätigung/Überschreibung durch den Bearbeiter (Vier-Augen über die Rolle des ISB/Assessors). +model ControlAssessment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + control String // Control-ID (mapping.json), z. B. "1.3.1" | "5.3.4-KI" + suggested Int? @map("suggested_value") // zuletzt berechneter Vorschlag (0–3) + confirmedValue Int @map("confirmed_value") // bestätigter/überschriebener Reifegrad (0–3) + target Int // Zielreifegrad zum Zeitpunkt der Bestätigung + justification String? // Pflichtbegründung bei Überschreibung nach unten (C5 §4.6) + confirmedById String? @map("confirmed_by_id") + confirmedAt DateTime @default(now()) @map("confirmed_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([tenantId, control]) + @@index([tenantId]) + @@map("control_assessments") +} + +// Umsetzungsdokumentation je ISA-Teilanforderung/Spiegelstrich (#10): der Bearbeiter hält +// im Wizard fest, ob der zugehörige Umsetzungshinweis (ImplementationHint, global) erledigt +// ist. Sind alle relevanten Hinweise eines Controls erledigt, zählt das als operativer +// Wirksamkeitsnachweis und hebt den Reifegrad-Vorschlag (src/server/soa-context.ts). +model ControlImplementation { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + reqId String @map("req_id") // ImplementationHint.reqId, z. B. "5.2.3-M2" + control String // Control-ID (denormalisiert für Aggregation je Control) + status String @default("offen") // offen | in_umsetzung | erledigt + note String? // Dokumentation der Umsetzung / Nachweisverweis + updatedById String? @map("updated_by_id") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([tenantId, reqId]) + @@index([tenantId]) + @@index([tenantId, control]) + @@map("control_implementations") +} + +model AuditLog { + id String @id @default(cuid()) + // Nullable: Plattform-Ereignisse (scope=platform, z. B. Superadmin-Login) haben keinen Mandantenbezug. + tenantId String? @map("tenant_id") + scope String @default("tenant") // tenant | platform + actorId String? @map("actor_id") + action String // create | update | delete | login | denied | export | … + entity String // z. B. asset, risk, user + entityId String? @map("entity_id") + before Json? + after Json? + createdAt DateTime @default(now()) @map("created_at") + + tenant Tenant? @relation(fields: [tenantId], references: [id]) + + @@index([tenantId, entity, entityId]) + @@index([tenantId, createdAt]) + @@map("audit_logs") +} + +// Generisches Aufgaben-/Freigabe-Modell (erweiterbar). Erster Typ: policy_approval +// (Richtlinien-Freigabe an eine konkrete Person). Kommentare/Statuswechsel historisiert. +// ── TISAX-Neustruktur Fundament (M0) ───────────────────────────────────────── +// Fachbereich einer Aufgabe/eines Controls. Kapitel→Domain-Mapping (ControlDomainMap) +// folgt in M3; hier nur die stabile Taxonomie als DB-Enum. +enum Domain { + GOVERNANCE + HR + PHYSICAL + BCM + IT + PROCUREMENT + COMPLIANCE + DATA_PROTECTION + PROTOTYPE +} + +// RACI-Rolle für Aufgaben-Mitwirkende (TaskParticipant folgt in M3). +enum RaciKind { + RESPONSIBLE + ACCOUNTABLE + CONSULTED + INFORMED +} + +// Schutz-/Klassifizierungslabel eines (primären) Informations-Assets — wird in M2 +// am Asset gesetzt (Info = primärer Asset, kein Extra-Objekt). +enum InfoLabel { + NONE + INFO_HIGH + INFO_VERY_HIGH + PROTOTYPE + PERSONAL_DATA +} + +model Task { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + type String // policy_approval | … + title String + description String? // freitextliche Beschreibung (analog Maßnahme) + status String @default("OPEN") // OPEN | DONE | REJECTED | CANCELLED + entityType String? @map("entity_type") // z. B. policy_document + entityId String? @map("entity_id") + entityRef String? @map("entity_ref") // Deep-Link-Referenz, z. B. Policy-Code + assigneeId String? @map("assignee_id") // "owner" (Contracts §1): wer bearbeiten/freigeben soll + createdById String? @map("created_by_id") + dueDate DateTime? @map("due_date") + // Wizard-Erweiterung (Contracts §1, Story F1) — bestehender policy_approval-Flow bleibt unberührt + priority String @default("mittel") // hoch | mittel | niedrig + origin String? // Herkunft/Trigger, z. B. "wizard:step3:isb_not_named" | "manual" + resources Json? // { tool?, budget?, personnel?, time? } + links Json? // { control?, risk?, document?, asset? } — polymorphe Verknüpfungen + resolvedById String? @map("resolved_by_id") + resolvedAt DateTime? @map("resolved_at") + // TISAX-Neustruktur Fundament (M0): Bereichs-Board (M3) baut hierauf auf. + domain Domain? // Fachbereich der Aufgabe (Default aus Kapitel→Domain-Mapping, M3) + orderIdx Int @default(0) @map("order_idx") // manuelle Sortierung je Bereich + // Cockpit (M3, 1.5): Wiedervorlage/Wirksamkeitsintervall. + recurrence String? // ISO-8601-Dauer/RRULE, z. B. "P1Y" → Folge-Task bei DONE (2.2) + remindAt DateTime? @map("remind_at") // Wiedervorlage-Erinnerung + effectiveUntil DateTime? @map("effective_until") // Wirksamkeitsintervall (↔ Evidence.validUntil) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + comments TaskComment[] + participants TaskParticipant[] + evidence Evidence[] + + @@index([tenantId, status]) + @@index([tenantId, assigneeId, status]) + @@index([tenantId, domain, status]) + @@map("tasks") +} + +// Cockpit (M3, 1.5): RACI-Mitwirkende zusätzlich zu assigneeId (= primär RESPONSIBLE). +// Ein Eintrag (auch CONSULTED/INFORMED) macht die Aufgabe für die Person sichtbar, +// ohne ihr den ganzen Bereich zu öffnen (Sichtbarkeitslogik 2.3). +model TaskParticipant { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + taskId String @map("task_id") + userId String @map("user_id") + raci RaciKind + + task Task @relation(fields: [taskId], references: [id], onDelete: Cascade) + + @@unique([tenantId, taskId, userId, raci]) + @@index([tenantId, userId]) + @@map("task_participants") +} + +// Cockpit (M3, 1.4): Kapitel/Control → Bereich + Default-RACI. Globaler Default +// (tenantId = null) plus optionaler Tenant-Override. Steuert die Default-Domain +// und die Default-Mitwirkenden bei der Aufgaben-Erzeugung (soa/gap/trigger). +model ControlDomainMap { + id String @id @default(cuid()) + tenantId String? @map("tenant_id") // null = globaler Default + control String // "3.1.4" oder Kapitel-Präfix "3" + domain Domain + raci RaciKind @default(RESPONSIBLE) + functionKey String? @map("function_key") // Default-verantwortliche Funktion (ISB, IT_LEAD, …) + + @@index([tenantId, control]) + @@index([control]) + @@map("control_domain_map") +} + +// Cockpit (M3, 1.6): Nachweis-/Evidence-Register. Task-taugliches, generisches +// Evidence-Modell (die bestehenden PolicyEvidence/SupplierEvidence sind +// domänenspezifische Register). „audit-ready" verlangt einen solchen Nachweis +// zusätzlich zur Vier-Augen-Freigabe (Auto-Completion-Deckel 2.2). +// validUntil koppelt an Task.effectiveUntil (Wiedervorlage). +model Evidence { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + title String + kind String // record | protocol | screenshot | export + fileRef String? @map("file_ref") + taskId String? @map("task_id") + control String? // Control-ID (z. B. "5.2.9") + validFrom DateTime? @map("valid_from") + validUntil DateTime? @map("valid_until") // ↔ Task.effectiveUntil + createdById String? @map("created_by_id") + createdAt DateTime @default(now()) @map("created_at") + + task Task? @relation(fields: [taskId], references: [id], onDelete: SetNull) + + incidentEvidence IncidentEvidence[] + + @@index([tenantId, control]) + @@index([tenantId, taskId]) + @@map("evidence") +} + +// ── Audit-Vorbereitung (VDA ISA) ────────────────────────────────────────────── +enum AuditType { + INTERNAL + EXTERNAL +} + +enum AuditStatus { + PLANNED + IN_PREPARATION + DONE +} + +// Ein geplantes Audit (intern oder externes Assessment). Übersichtsseite listet diese. +model Audit { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + type AuditType + title String + plannedDate String? @map("planned_date") // Freitext, z. B. "24.–25.09.2026" + scope String? + assessmentLevel String? @map("assessment_level") // AL2/AL3 (extern) + provider String? // Prüfdienstleister (extern) + auditorUserId String? @map("auditor_user_id") // interner Auditor + status AuditStatus @default(PLANNED) + preparationDeadline DateTime? @map("preparation_deadline") + result String? // Ergebnis nach Abschluss + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + evidenceItems AuditEvidenceItem[] + + @@index([tenantId, status]) + @@map("audits") +} + +// Bereitzustellender Nachweis je Control für ein Audit (aus ISA vorbelegt, Ansprechpartner zugeordnet). +model AuditEvidenceItem { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + auditId String @map("audit_id") + control String + title String // Nachweisart + reqId String? @map("req_id") // ↔ PolicyRequirement / ImplementationHint + assignedUserId String? @map("assigned_user_id") + assignedFunctionKey String? @map("assigned_function_key") + status String @default("offen") // offen | bereitgestellt | ueberfaellig + evidenceId String? @map("evidence_id") // ↔ Evidence (Upload) + taskId String? @map("task_id") + createdAt DateTime @default(now()) @map("created_at") + + audit Audit @relation(fields: [auditId], references: [id], onDelete: Cascade) + + @@index([tenantId, auditId]) + @@index([tenantId, assignedUserId, status]) + @@map("audit_evidence_items") +} + +// „Beschreibung der Umsetzung" je Anforderung (VDA-ISA-Spalte 4). Tenant-weit wiederverwendbar. +model ControlDescription { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + control String + reqId String @map("req_id") // ↔ PolicyRequirement.reqId + draftText String? @map("draft_text") + sourceRef String? @map("source_ref") // Dokument/Abschnitt + confidence String? // high | medium | low + status String @default("open") // open | draft | confirmed + openAnswer String? @map("open_answer") + updatedById String? @map("updated_by_id") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([tenantId, reqId]) + @@index([tenantId, control]) + @@map("control_descriptions") +} + +model TaskComment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + taskId String @map("task_id") + authorId String? @map("author_id") + kind String @default("comment") // comment | approve | reject | submit + body String + createdAt DateTime @default(now()) @map("created_at") + + task Task @relation(fields: [taskId], references: [id], onDelete: Cascade) + + @@index([tenantId, taskId]) + @@map("task_comments") +} + +// ── Richtlinien & Verfahren (VDA-ISA 2027 Vorlagenpaket) ────────────────────── +// Dokumente werden aus ihrer echten Markdown-Vorlage gerendert; Variablen, +// Feature-Flags und Baseline-Parameter sind die eine Pflegestelle (§7). + +enum PolicyDocType { + LEITLINIE // L00 + RICHTLINIE // R01–R14 + VERFAHREN // VA-01–VA-13 + REGISTER // verwaltete Tabellen (Baseline, Nachweisregister, …) + HANDBUCH // Anwender-Handbuch + EIGENES // Word-Upload +} + +enum PolicyStatus { + ENTWURF + IN_FREIGABE + FREIGEGEBEN + ARCHIVIERT +} + +model PolicyDocument { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + code String // L00 | R01..R14 | VA-01..VA-13 | BASELINE | NACHWEIS | ISA_MAPPING + type PolicyDocType + title String + version String @default("1.0") + status PolicyStatus @default(FREIGEGEBEN) + owner String? + policyCode String? @map("policy_code") // bei VA: operationalisierte Richtlinie (R..) + fulfills String[] @default([]) // bei VA: erfüllte Anforderungs-IDs + rawMarkdown String @map("raw_markdown") // Vorlagen-Markdown mit Platzhaltern + orderIdx Int @default(0) @map("order_idx") + // Freigabe-Workflow (Vier-Augen): wer eingereicht/genehmigt hat + submittedBy String? @map("submitted_by") + approvedBy String? @map("approved_by") + approvedAt DateTime? @map("approved_at") + // Schutzbedarf-/TISAX-Level-Override je Richtlinie: null = global, "AL2" | "AL3" + protectionOverride String? @map("protection_override") + // Fachbereich der Richtlinie (aus primärem Control abgeleitet, überschreibbar) — + // für die „Richtlinien nach Fachbereich"-Ansicht + Zuständigkeit. + domain Domain? + // Lifecycle (nicht-destruktiver Re-Import): gesetzt, wenn das Dokument nicht mehr + // im Vorlagenpaket enthalten ist. null = aktiv. Orthogonal zum Freigabe-`status`. + archivedAt DateTime? @map("archived_at") + // AP5 — Dokumentenlenkung (A.5.1: Überprüfung „in geplanten Abständen"). reviewCycle + // ist der Prüfzyklus (jährlich/…); nextReviewAt der berechnete nächste Prüftermin. + reviewCycle String? @map("review_cycle") + nextReviewAt DateTime? @map("next_review_at") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + acknowledgements PolicyAcknowledgement[] + versionHistory PolicyDocumentVersion[] + + @@unique([tenantId, code]) + @@index([tenantId]) + @@index([tenantId, nextReviewAt]) + @@map("policy_documents") +} + +// AP5 — Lesebestätigung je Richtlinienversion (SPEC §4.6; Nachweis für Klausel 7.3 +// und Control A.6.3). Ein Nutzer bestätigt eine konkrete Dokumentversion genau einmal. +model PolicyAcknowledgement { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + policyDocumentId String @map("policy_document_id") + version String + userId String @map("user_id") + acknowledgedAt DateTime @default(now()) @map("acknowledged_at") + document PolicyDocument @relation(fields: [policyDocumentId], references: [id], onDelete: Cascade) + + @@unique([tenantId, policyDocumentId, userId, version]) + @@index([tenantId]) + @@index([policyDocumentId, version]) + @@map("policy_acknowledgements") +} + +// AP5 — Änderungshistorie je Dokumentversion (Momentaufnahme bei Prüfung/Neuversion). +model PolicyDocumentVersion { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + policyDocumentId String @map("policy_document_id") + version String + title String + changeNote String? @map("change_note") + createdBy String? @map("created_by") + createdAt DateTime @default(now()) @map("created_at") + document PolicyDocument @relation(fields: [policyDocumentId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@index([policyDocumentId]) + @@map("policy_document_versions") +} + +model PolicyRequirement { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + // Framework-Dimension (AP1): Anforderungen tragen ihren Namensraum, damit der + // Re-Import framework-scoped abgleicht und ein ISO-Import die TISAX-Anforderungen + // (und umgekehrt) NICHT archiviert. Backfill der Bestandsdaten auf TISAX. + framework Framework @default(TISAX) + reqId String @map("req_id") // z. B. 4.1.2-M1 (TISAX) / A.5.15-1 (ISO) + policyCode String @map("policy_code") // R08 + control String // 4.1.2 + obligation String // MUSS | SOLL + condition String? // FLAG_… oder null + requirement String + implementation String + vaCodes String[] @default([]) @map("va_codes") // operationalisierende Verfahren + nachweisLink String? @map("nachweis_link") + // Lifecycle (nicht-destruktiver Re-Import): gesetzt, wenn die Anforderung nicht mehr + // im Vorlagenpaket enthalten ist. null = aktiv. + archivedAt DateTime? @map("archived_at") + createdAt DateTime @default(now()) @map("created_at") + + @@unique([tenantId, reqId]) + @@index([tenantId]) + @@index([tenantId, control]) + @@index([tenantId, framework]) + @@map("policy_requirements") +} + +// Wizard-Variablen und Feature-Flags (variables.schema.json) — eine Pflegestelle +model PolicyVariable { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + key String // UPPER_SNAKE, z. B. PW_MIN_LENGTH / FLAG_CLOUD_USED + title String + kind String // string | boolean + groupName String? @map("group_name") + value String // aktueller Wert (Default aus Schema); Flags als "true"/"false" + required Boolean @default(false) + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([tenantId, key]) + @@index([tenantId]) + @@map("policy_variables") +} + +model PolicyBaselineParam { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + blId String @map("bl_id") // BL-IAM-01 + section String // "1. Identitäts- und Zugriffsmanagement" + name String + vorgabe String // Vorlagentext (kann {{VARIABLE}} enthalten) + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + @@unique([tenantId, blId]) + @@index([tenantId]) + @@map("policy_baseline_params") +} + +model PolicyEvidence { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + nr Int + policyCode String @map("policy_code") + nachweis String + quelle String + verantwortlich String + turnus String + createdAt DateTime @default(now()) @map("created_at") + + @@index([tenantId]) + @@map("policy_evidence") +} + +// ── Verwaltete Register-Tabellen (§7b) ─────────────────────────────────────── + +// Verschlüsselungsmechanismen-Register (VA-07 Kryptokonzept & Schlüsselverwaltung) +model CryptoEntry { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + dienst String + schluessel String + algorithmus String? + ablaufdatum DateTime? @map("ablauf_datum") + verantwortlich String + speicherort String? + baselineRef String? @map("baseline_ref") // z. B. BL-CRY-02 + notes String? + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@index([tenantId]) + @@map("crypto_entries") +} + +// Klassifizierungs-Handhabungsmatrix (R02 / VA-08) — Schutzklassen × Aspekte +model ClassificationClass { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String + description String? + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + rules HandlingRule[] + + @@index([tenantId]) + @@map("classification_classes") +} + +model HandlingAspect { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String + category String? + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + rules HandlingRule[] + + @@index([tenantId]) + @@map("handling_aspects") +} + +model HandlingRule { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + classId String @map("class_id") + aspectId String @map("aspect_id") + text String + + class ClassificationClass @relation(fields: [classId], references: [id], onDelete: Cascade) + aspect HandlingAspect @relation(fields: [aspectId], references: [id], onDelete: Cascade) + + @@unique([classId, aspectId]) + @@index([tenantId]) + @@map("handling_rules") +} + +// Risiko-Bewertungsmatrix (R03 / VA-09) — zentrale Pflegestelle (Defaults FB-80-04) +model RiskMatrixClass { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String // Niedrig | Mittel | Hoch | Kritisch + maxScore Int @map("max_score") // obere Schwelle des Risikowerts + acceptance String // Akzeptanzinstanz + tone String // ok | warn | orange | risk + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + @@index([tenantId]) + @@map("risk_matrix_classes") +} + +model RiskEwLevel { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + level Int + label String + definition String + createdAt DateTime @default(now()) @map("created_at") + + @@index([tenantId]) + @@map("risk_ew_levels") +} + +model RiskDamageDimension { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String + levels Json // { "1": "…", "2": "…", "3": "…", "4": "…" } + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + @@index([tenantId]) + @@map("risk_damage_dimensions") +} + +// Anwender-Handbuch (§9.7) — kuratierte Themen mit Deep-Links; Werte via Templating +model HandbookTopic { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + category String + title String + bodyMd String @map("body_md") // Markdown mit {{VARIABLE}} (bleibt via Baseline synchron) + sourceRefs String[] @default([]) @map("source_refs") // Deep-Links, z. B. R08#4.1.2 + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@index([tenantId]) + @@map("handbook_topics") +} + +// Generisches verwaltetes Register (GAP-Report WP3.0): benannte Register mit +// Register-ID (REG-…), definierten Pflichtspalten, Review-Turnus und optionalen +// Cross-Links an Lieferanten (R13/VA-10) und Asset-Inventar (R02/VA-08). +model ManagedRegister { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + code String // REG-PROJECTS, REG-SW-WHITELIST, … + title String + description String? + columns Json @default("[]") // [{ key, label }] Pflichtspalten + reviewCycle String? @map("review_cycle") + responsible String? + supplierLink Boolean @default(false) @map("supplier_link") // Cross-Link Lieferant (Asset) + assetLink Boolean @default(false) @map("asset_link") // Cross-Link Asset + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + rows RegisterRow[] + + @@unique([tenantId, code]) + @@index([tenantId]) + @@map("managed_registers") +} + +model RegisterRow { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + registerId String @map("register_id") + values Json @default("{}") // { spaltenKey: wert } + supplierRef String? @map("supplier_ref") // Asset-ID (Lieferant) + assetRef String? @map("asset_ref") // Asset-ID + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + register ManagedRegister @relation(fields: [registerId], references: [id], onDelete: Cascade) + + @@index([tenantId, registerId]) + @@map("register_rows") +} + +// ── Objekt-Review-Status (Story F2) ───────────────────────────────────────── +// Wiederverwendbares, generalisiertes Review-Status-Enum (Contracts §2): Wizard- +// Gates und – ab Story A3 – beliebige Fach-Objekte nutzen es. Regel: „Nur +// `validiert` zählt als bestätigt." `zurueckgewiesen` erlaubt Rückweisung durch +// eine validierende Rolle (`external_validator`, RBAC-Recht `validate_objects`). +enum ObjectReviewStatus { + offen + in_bearbeitung + zur_validierung + validiert + zurueckgewiesen +} + +// ── Onboarding-Wizard (Story A1-1) ────────────────────────────────────────── +// Persistenter, resumierbarer Fortschritt je Mandant und Wizard-Schritt. +// Der Schritt-Status treibt das "Weiter"-Gate: „Weiter" ist gesperrt, solange +// der Vorgänger-Schritt nicht `validiert` ist. Ab F2 nutzt der Schritt-Status das +// generalisierte `ObjectReviewStatus` (inkl. `zurueckgewiesen`). +model OnboardingProgress { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + stepKey String @map("step_key") // einer der Registry-Keys (scoping, context, …) + status ObjectReviewStatus @default(offen) + reviewComment String? @map("review_comment") + reviewerId String? @map("reviewer_id") + updatedAt DateTime @updatedAt @map("updated_at") + createdAt DateTime @default(now()) @map("created_at") + + @@unique([tenantId, stepKey]) + @@index([tenantId]) + @@map("onboarding_progress") +} + +// ── TISAX-Neustruktur Ebene 1 „Fundament" (M1) ─────────────────────────────── +// Echte Zuordnung ISMS-Funktion → User(n) (löst die read-only Rollen-Variablen ab). +// Eine Funktion (functionKey, z. B. ISB/PM/BCM/AUDITOR_INT/DPO) kann mehrere Halter +// haben (Asset-/Risk-Owner) oder unbesetzt sein (kein Eintrag → Task „Funktion +// besetzen"). `userId` = zugewiesener Account; `invitedEmail` = per SEC2 eingeladener, +// noch nicht (voll) aktiver Account; `domain` = Default-Bereich (Sichtbarkeit, Ebene 3). +model ProjectFunctionAssignment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + functionKey String @map("function_key") // ISB, PM, HR_LEAD, IT_LEAD, BCM, AUDITOR_INT, DPO … + userId String? @map("user_id") // null = unbesetzt → erzeugt Task „Funktion besetzen" + domain Domain? // Default-Bereich dieser Funktion (Sichtbarkeit) + invitedEmail String? @map("invited_email") // Einladung, falls Account noch nicht existiert + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@index([tenantId, functionKey]) + @@map("project_function_assignments") +} + +// Wizard-Scope (Story A2-2): Geltungsbereich des Onboarding-Scopings je Mandant. +// Prüfziele (Informationssicherheit stets aktiv; Prototypenschutz/Datenschutz optional), +// Geltungsbereich, Standorte und Ausschlüsse. Speist zusammen mit dem Assessment-Level +// (Schutzbedarf-Flags) den Scope-Filter (src/lib/scope-filter.ts) → aktive Anforderungen. +model WizardScope { + id String @id @default(cuid()) + tenantId String @unique @map("tenant_id") + pruefziele String[] @default(["informationssicherheit"]) + geltungsbereich String? + standorte String[] @default([]) + ausschluesse String? + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@index([tenantId]) + @@map("wizard_scopes") +} + +// Versionsstand des Richtlinien-Vorlagenpakets je Mandant (Story B6). Hält die +// zuletzt kontrolliert übernommene Paket-Version. Ein Update wird nicht still +// überschrieben: Abweichung zur aktuellen Paketversion → Diff/Übernahme (B6-2). +model PolicyPackageState { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + // Framework-Dimension (AP1): je Mandant EIN Paketstand PRO Framework — sonst merkt + // sich ein Doppel-Mandant nur eine Version (Falle 1.2). Backfill auf TISAX. + framework Framework @default(TISAX) + importedVersion String? @map("imported_version") // zuletzt übernommene Paketversion + importedAt DateTime? @map("imported_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([tenantId, framework]) + @@index([tenantId]) + @@map("policy_package_states") +} + +// Framework-Dimension (AP1): welche Compliance-Rahmenwerke ein Mandant führt. Ein +// Mandant kann TISAX, ISO 27001 oder beide führen — die Zeilen steuern, welche +// Mappings importiert und welche Sichtbarkeits-Flags (AP2) gesetzt werden. +enum Framework { + ISO_27001 + TISAX +} + +model TenantFramework { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + framework Framework + isPrimary Boolean @default(false) @map("is_primary") + config Json? // z. B. { tisaxLevel: "AL3" } bzw. { certScope, certBodyTarget } + createdAt DateTime @default(now()) @map("created_at") + + @@unique([tenantId, framework]) + @@index([tenantId]) + @@map("tenant_frameworks") +} + +// AP3 — Anwendbarkeitserklärung (Statement of Applicability, ISO/IEC 27001:2022 6.1.3 d). +// Je Mandant + Framework eine Zeile pro Control (Annex A / ISO 27002). `applicable`, +// `justification` und der Umsetzungsstatus sind normative Pflichtangaben — auch die +// AUSSCHLUSS-Begründung steht in `justification`. Vorbefüllung aus mapping-iso.json. +model SoaEntry { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + framework Framework + control String // "A.5.15" + title String? // Control-Titel (aus dem Mapping, Anzeige/Export) + applicable Boolean @default(true) + justification String @default("") // Begründung Einbeziehung ODER Ausschluss + source String? // Risiko-ID / gesetzliche / vertragliche Anforderung + implementationStatus String @default("geplant") @map("implementation_status") // umgesetzt | teilweise | geplant + ownerId String? @map("owner_id") + policyCode String? @map("policy_code") + evidenceId String? @map("evidence_id") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([tenantId, framework, control]) + @@index([tenantId]) + @@index([tenantId, framework]) + @@map("soa_entries") +} + +// AP4 — 9.1 Überwachung, Messung, Analyse und Bewertung (Kennzahlen). +model Kpi { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + name String + description String? + dataSource String? @map("data_source") // Woher der Messwert stammt (9.1 b) + unit String? // %, Anzahl, Tage … + target String? // Zielwert (frei, z. B. "> 95%") + cadence String @default("monatlich") // Turnus (9.1 c/d) + ownerId String? @map("owner_id") + active Boolean @default(true) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + values KpiValue[] + + @@index([tenantId]) + @@map("kpis") +} + +model KpiValue { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + kpiId String @map("kpi_id") + period String // "2026-Q1" / "2026-03" + value String // gemessener Wert (frei) + note String? + recordedAt DateTime @default(now()) @map("recorded_at") + kpi Kpi @relation(fields: [kpiId], references: [id], onDelete: Cascade) + + @@unique([tenantId, kpiId, period]) + @@index([tenantId]) + @@index([kpiId]) + @@map("kpi_values") +} + +// AP4 — 9.3 Managementbewertung. +model ManagementReview { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + reviewDate DateTime @map("review_date") + status String @default("entwurf") // entwurf | abgeschlossen + inputs String? // Eingaben nach 9.3.2 (strukturierter Text) + results String? // Ergebnisse nach 9.3.3 + ownerId String? @map("owner_id") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + decisions ManagementReviewDecision[] + + @@index([tenantId]) + @@map("management_reviews") +} + +model ManagementReviewDecision { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + reviewId String @map("review_id") + decision String + ownerId String? @map("owner_id") + dueDate DateTime? @map("due_date") + status String @default("offen") // offen | erledigt + review ManagementReview @relation(fields: [reviewId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@index([reviewId]) + @@map("management_review_decisions") +} + +// AP4 — 10.2 Nichtkonformität und Korrekturmaßnahme. +model Nonconformity { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + refNo String @map("ref_no") // NC-2026-0001 + source String // Herkunft (Audit, Vorfall, Beschwerde …) 10.2 a + description String + immediateCorrection String? @map("immediate_correction") // Sofortkorrektur 10.2 a + status String @default("offen") // offen | in_bearbeitung | abgeschlossen + ownerId String? @map("owner_id") + detectedAt DateTime @default(now()) @map("detected_at") + closedAt DateTime? @map("closed_at") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + actions CorrectiveAction[] + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@map("nonconformities") +} + +model CorrectiveAction { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + nonconformityId String @map("nonconformity_id") + rootCause String? @map("root_cause") // Ursachenanalyse 10.2 b + action String // Maßnahme 10.2 c/d + ownerId String? @map("owner_id") + dueDate DateTime? @map("due_date") + status String @default("geplant") // geplant | umgesetzt + effectivenessCheck String? @map("effectiveness_check") // Wirksamkeitsbewertung 10.2 d/e + effectivenessConfirmedAt DateTime? @map("effectiveness_confirmed_at") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + nonconformity Nonconformity @relation(fields: [nonconformityId], references: [id], onDelete: Cascade) + + @@index([tenantId]) + @@index([nonconformityId]) + @@map("corrective_actions") +} + +// ============================================================================= +// Globale Richtlinien-VORLAGEN (Plattform-Ebene, KEIN tenantId/RLS — analog +// ImplementationHint). Master-Quelle für den Mandanten-Import. Der Plattform-Admin +// bearbeitet einen Entwurf (DRAFT) und veröffentlicht ihn als neue Version (PUBLISHED, +// unveränderlich). Neue Mandanten erhalten automatisch die neueste veröffentlichte +// Version; bestehende Mandanten werden informiert und übernehmen nicht-destruktiv +// per Opt-in (bestehender Update-Flow). Inhalte je Sprache (`locale` = de|en). +// ============================================================================= +enum PolicyTemplateStatus { + DRAFT + PUBLISHED + ARCHIVED +} + +model PolicyTemplateVersion { + id String @id @default(cuid()) + // Framework-Dimension (AP1): dieselbe Versionsnummer kann je Framework existieren + // (ISO 2.1 ≠ TISAX 2.1) → Eindeutigkeit erst mit dem Framework (Falle 1.2). + framework Framework @default(TISAX) + version String // kanonische Paketversion, z. B. "2.1" + status PolicyTemplateStatus @default(DRAFT) + notes String? // Änderungshinweis (Changelog) für die Mandanten-Benachrichtigung + publishedBy String? @map("published_by") + publishedAt DateTime? @map("published_at") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + documents PolicyTemplateDoc[] + requirements PolicyTemplateRequirement[] + variables PolicyTemplateVariable[] + baselineParams PolicyTemplateBaselineParam[] + evidence PolicyTemplateEvidence[] + + @@unique([framework, version]) + @@index([status]) + @@map("policy_template_versions") +} + +model PolicyTemplateDoc { + id String @id @default(cuid()) + versionId String @map("version_id") + locale String // de | en + code String // L00 | R01..R14 | VA-.. | BASELINE | NACHWEIS + type PolicyDocType + title String + docVersion String @default("1.0") @map("doc_version") + policyCode String? @map("policy_code") + fulfills String[] @default([]) + domain Domain? + rawMarkdown String @map("raw_markdown") + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + version PolicyTemplateVersion @relation(fields: [versionId], references: [id], onDelete: Cascade) + + @@unique([versionId, locale, code]) + @@index([versionId, locale]) + @@map("policy_template_docs") +} + +model PolicyTemplateRequirement { + id String @id @default(cuid()) + versionId String @map("version_id") + locale String + reqId String @map("req_id") + policyCode String @map("policy_code") + control String + obligation String // MUSS | SOLL + condition String? + requirement String + implementation String + vaCodes String[] @default([]) @map("va_codes") + nachweisLink String? @map("nachweis_link") + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + version PolicyTemplateVersion @relation(fields: [versionId], references: [id], onDelete: Cascade) + + @@unique([versionId, locale, reqId]) + @@index([versionId, locale]) + @@map("policy_template_requirements") +} + +model PolicyTemplateVariable { + id String @id @default(cuid()) + versionId String @map("version_id") + locale String + key String // UPPER_SNAKE + title String + kind String // string | boolean + groupName String? @map("group_name") + value String // Default-Wert aus dem Schema (Flags "true"/"false") + required Boolean @default(false) + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + version PolicyTemplateVersion @relation(fields: [versionId], references: [id], onDelete: Cascade) + + @@unique([versionId, locale, key]) + @@index([versionId, locale]) + @@map("policy_template_variables") +} + +model PolicyTemplateBaselineParam { + id String @id @default(cuid()) + versionId String @map("version_id") + locale String + blId String @map("bl_id") + section String + name String + vorgabe String + orderIdx Int @default(0) @map("order_idx") + createdAt DateTime @default(now()) @map("created_at") + + version PolicyTemplateVersion @relation(fields: [versionId], references: [id], onDelete: Cascade) + + @@unique([versionId, locale, blId]) + @@index([versionId, locale]) + @@map("policy_template_baseline_params") +} + +model PolicyTemplateEvidence { + id String @id @default(cuid()) + versionId String @map("version_id") + locale String + nr Int + policyCode String @map("policy_code") + nachweis String + quelle String + verantwortlich String + turnus String + createdAt DateTime @default(now()) @map("created_at") + + version PolicyTemplateVersion @relation(fields: [versionId], references: [id], onDelete: Cascade) + + @@unique([versionId, locale, nr]) + @@index([versionId, locale]) + @@map("policy_template_evidence") +} + +// Wizard-Fakten (Story B3): wiederverwendbare Antworten des Fragebogens (Schritt 2, +// „context"). Ein Fakt je Frage-Key und Mandant; `value` als JSON (bool/string/number). +// Der Fragebogen schreibt NUR Fakten/Flags — nie die gesperrten Zentralvariablen +// (Organisation/Rollen/Schutzbedarf, nur in /settings pflegbar). +model WizardFact { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + key String // Frage-/Fakt-Key (z. B. Q-FEAT-02) + section String // Fragebogen-Abschnitt A|B|C|D|E|F + value Json // Antwortwert (bool | string | number) + updatedAt DateTime @updatedAt @map("updated_at") + createdAt DateTime @default(now()) @map("created_at") + + @@unique([tenantId, key]) + @@index([tenantId]) + @@map("wizard_facts") +} + +// Umsetzungshinweis je Teilanforderung (Story B5, Fachcontent C6). GLOBALER +// Katalog-Content (identisch je Mandant) → kein tenantId/RLS. Ein Eintrag je +// Anforderungs-ID (z. B. 1.1.1-M1) mit organisatorischer/technischer Umsetzung, +// typischen Nachweisen, Vorlagen-Verweis, Ressourcenindikation und AL-Filter. +model ImplementationHint { + id String @id @default(cuid()) + reqId String @unique @map("req_id") // 1.1.1-M1 + control String // 1.1.1 + stufe String // MUSS | SOLL | HOCH | SEHR HOCH + requirement String // Anforderungstext + organisational String // organisatorische Umsetzung + technical String // technische Umsetzung + evidence String // typische Nachweise + template String? // Vorlagen-Verweis (L00, R08, …) + resources String // Ressourcenindikation + alFilter String @map("al_filter") // "AL2 + AL3" | "AL3" + procurement Boolean @default(false) // Ressourcen deuten Beschaffungs-/Toolbudget-Bedarf an + createdAt DateTime @default(now()) @map("created_at") + + @@index([control]) + @@map("implementation_hints") +} + +// ============================================================================= +// SEC1 — Mail-Fundament +// ============================================================================= + +/// Versandprotokoll jeder Mail (Auditierbarkeit + Idempotenz). +/// +/// `tenantId` ist nullable: Plattform-Mails (Superadmin-Kontext) haben keinen +/// Mandantenbezug und laufen unter scope=platform — analog zu AuditLog. +/// `dedupeKey` ist plattformweit unique und verhindert Doppelversand: der Insert +/// selbst ist die Sperre (kein Read-then-Write-Rennen zwischen App-Instanzen). +/// +/// Bewusst NICHT gespeichert: Mail-Inhalt und alle Token/Secrets. Nur Metadaten, +/// die Zustellprobleme nachvollziehbar machen (SEC1 §8). +model MailLog { + id String @id @default(cuid()) + tenantId String? @map("tenant_id") + scope String @default("tenant") // tenant | platform + to String + template String + locale String @default("de") + status String @default("pending") // pending | sent | failed | bounced | suppressed + providerMessageId String? @map("provider_message_id") + error String? + attempts Int @default(0) + dedupeKey String? @unique @map("dedupe_key") + createdAt DateTime @default(now()) @map("created_at") + sentAt DateTime? @map("sent_at") + + @@index([tenantId, createdAt]) + @@index([status]) + @@map("mail_logs") +} + +/// Benachrichtigungs-Einstellung je Nutzer und Ereignistyp. +/// +/// Default ist opt-in: fehlt eine Zeile, gilt `email = true`. Die Zeile wird erst +/// geschrieben, wenn der Nutzer bewusst abweicht (UI folgt später) — deshalb ist +/// das Fehlen der Zeile der Normalfall und kein Datenmangel. +/// Transaktionsmails (Reset, Passwortwechsel) sind sicherheitsrelevant und +/// unterliegen dieser Steuerung NICHT (siehe src/server/mail/notifications.ts). +model NotificationPreference { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + userId String @map("user_id") + eventType String @map("event_type") // task_assigned | task_approval_requested | task_decided | task_due + email Boolean @default(true) + locale String? + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@unique([userId, eventType]) + @@index([tenantId]) + @@map("notification_preferences") +} + +// ============================================================================= +// SEC2 — Passwort-Self-Service, E-Mail-Änderung, Sessions +// ============================================================================= + +/// Einmal-Token für Passwort-Reset und E-Mail-Änderung. +/// +/// Das **Rohtoken** (32 Byte CSPRNG, base64url) steht ausschließlich im Link und +/// wird nie gespeichert oder geloggt — in der DB liegt nur sein SHA-256-Hash. +/// Der Lookup erfolgt über den Hash; der Vergleich läuft in konstanter Zeit. +/// +/// Gilt für **beide** Auth-Domänen: `principalType` unterscheidet Mandanten- +/// Nutzer und Plattform-Admins. `tenantId` ist nur bei `tenant_user` gesetzt und +/// trägt die RLS; Plattform-Zeilen haben `tenantId = null` und werden — wie bei +/// AuditLog und MailLog — über den rohen Client geschrieben. +model AuthToken { + id String @id @default(cuid()) + principalType String @map("principal_type") // tenant_user | platform_admin + principalId String @map("principal_id") + tenantId String? @map("tenant_id") + type String // password_reset | email_change + tokenHash String @unique @map("token_hash") + /// Nur bei type=email_change: die zu bestätigende neue Adresse. + newEmail String? @map("new_email") + expiresAt DateTime @map("expires_at") + usedAt DateTime? @map("used_at") + requestIp String? @map("request_ip") + createdAt DateTime @default(now()) @map("created_at") + + @@index([principalType, principalId, type]) + @@index([expiresAt]) + @@map("auth_tokens") +} + +// ============================================================================= +// Backup/DSGVO-Lane — GLOBALE Modelle (kein tenant_id, kein RLS, analog Kataloge) +// ============================================================================= + +/// Löschnachweis (Art. 17 DSGVO). GLOBAL — bewusst NICHT tenant-scoped/kein RLS, +/// damit der Nachweis eine Mandanten-Löschung/Offboarding überdauert (der Mandant +/// und seine RLS-Policies existieren danach ggf. nicht mehr). Enthält nur +/// Metadaten (wer/wann/Scope/Zähler), KEINE gelöschten Personendaten selbst. +model DeletionCertificate { + id String @id @default(cuid()) + /// tenant | person + scope String + /// Betroffener Mandant (als lose Referenz; kein FK, überlebt die Löschung). + tenantId String? @map("tenant_id") + tenantSlug String? @map("tenant_slug") + /// Bei scope=person: betroffene globale Identity (lose Referenz). + subjectIdentityId String? @map("subject_identity_id") + /// Bei scope=person: E-Mail zum Zeitpunkt der Löschung (Nachweis, pseudonymisierbar). + subjectEmail String? @map("subject_email") + actorId String? @map("actor_id") + /// Zeilenzahlen je Modell, die HART gelöscht wurden (JSON: {model: count}). + deletedCounts Json @default("{}") @map("deleted_counts") + /// Zeilenzahlen je Modell, die ANONYMISIERT wurden (Nachweispflicht). + anonymizedCounts Json @default("{}") @map("anonymized_counts") + /// Optionaler Verweis auf den Portabilitäts-/Offboarding-Snapshot. + snapshotId String? @map("snapshot_id") + reason String? + createdAt DateTime @default(now()) @map("created_at") + + @@index([tenantId]) + @@index([subjectIdentityId]) + @@map("deletion_certificates") +} + +/// Tombstone/Löschliste (KONFZEPT §6 „Backups vs. Löschung"). GLOBAL — überlebt +/// einen Tenant-Restore bewusst (nicht in TENANT_MODELS), damit ein alter Snapshot +/// gelöschte/anonymisierte PII NICHT wieder zurückbringt: `applyTombstones` wird am +/// Ende jedes Restore erneut angewandt. Enthält KEINE PII, nur die Regel, wie eine +/// wiederkehrende Zeile erneut zu behandeln ist (löschen bzw. anonymisieren). +model TombstoneEntry { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + /// Prisma-Modellname der betroffenen Tabelle (z. B. "User"). + model String + /// Prisma-Feldname des Match-Schlüssels (i. d. R. "id"). + targetField String @map("target_field") + /// Wert des Match-Schlüssels (cuid der betroffenen Zeile). + targetValue String @map("target_value") + /// delete | anonymize + action String + /// Bei action=anonymize: Feld→Ersatzwert (Tombstone), JSON. + anonymizedFields Json @default("{}") @map("anonymized_fields") + reason String? + createdAt DateTime @default(now()) @map("created_at") + + @@index([tenantId]) + @@unique([tenantId, model, targetValue]) + @@map("tombstone_entries") +} + +/// Betreiber-Portal: Status eines im Hintergrund ausgeführten Backup-/DSGVO-Jobs +/// (Portal-Restore, Export-jetzt, DSGVO-Zustellung). GLOBAL (kein tenant_id-RLS, +/// analog DeletionCertificate) — die Jobs sind eine Plattform-/Betreiber-Fähigkeit. +/// Die Server-Action enqueued nur + legt hier die Zeile an; der Worker (BullMQ) +/// führt aus und schreibt Status/Ergebnis zurück (KONZEPT §4). Enthält KEINE PII +/// und KEINE Secrets — nur Ausführungs-Metadaten. +model BackupJob { + id String @id @default(cuid()) + /// tenant_restore | tenant_export | dsgvo_export + kind String + /// queued | running | done | failed + status String @default("queued") + /// Betroffener Mandant (lose Referenz; kein FK). + tenantId String @map("tenant_id") + tenantSlug String? @map("tenant_slug") + /// Bei dsgvo_export (Per-Person): betroffene globale Identity (lose Referenz). + subjectIdentityId String? @map("subject_identity_id") + /// Handelnder Plattform-Admin. + actorId String? @map("actor_id") + /// Bei tenant_restore/dsgvo_export: gewählter Sicherungspunkt. + snapshotId String? @map("snapshot_id") + /// Job-Parameter (JSON, ohne Secrets) — z. B. reason, includeFiles. + params Json @default("{}") + /// Ergebnis (JSON, ohne PII) — z. B. Zeilenzahlen, Pre-Restore-Snapshot-Id. + result Json? + error String? + /// DSGVO-Zustellung: Token für den zeitlich begrenzten, signierten Download. + downloadToken String? @unique @map("download_token") + downloadExpiresAt DateTime? @map("download_expires_at") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@index([tenantId]) + @@index([status]) + @@map("backup_jobs") +} + +// ── Incident-Management (Modul „Vorfälle", IM-A) ───────────────────────────── +// Fachkonzept: docs/KONZEPT-incidents.md. IM-A = Fundament + Kern-Lifecycle/UI. +// Timer-/Meldepflicht-LOGIK (Fristenwerte werden nur als Felder vorbereitet) = IM-B, +// Inbound-Mail = IM-D, Maßnahmen-Detailausbau = IM-C. + +// §4-Taxonomie der Vorfall-Kategorien. +enum IncidentCategory { + malware // Schadsoftware + phishing // Phishing / Social Engineering + unauthorized_access // Unbefugter Zugriff + data_loss // Datenabfluss / -verlust + outage // Systemausfall / Verfügbarkeit + physical // Physisch (Zutritt / Diebstahl) + misconfiguration // Fehlbedienung / Konfiguration + supplier // Lieferant / Drittpartei + prototype_customer_data // Prototyp / Kundendaten (TISAX) + other // Sonstiges +} + +// §3 Statusmodell (Primärfluss + Wiedereröffnet). +enum IncidentStatus { + neu + triage + in_bearbeitung + eingedaemmt + behoben + abgeschlossen + wiedereroeffnet +} + +model Incident { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + // Kennung je Mandant/Jahr, Anzeige "INC-2026-0042". + refNo String @map("ref_no") + + // Basis + title String + description String? + source String @default("manual") // manual | email (Kanal/Quelle §2) + reporterName String? @map("reporter_name") + reporterContact String? @map("reporter_contact") + + // Zeiten (§4) + occurredAt DateTime? @map("occurred_at") // Eintritt + detectedAt DateTime? @map("detected_at") // Entdeckung + reportedAt DateTime? @map("reported_at") // interne Meldung + + // Kategorisierung & Betroffenheit + category IncidentCategory @default(other) + impactC Int @default(0) @map("impact_c") // 0–4 + impactI Int @default(0) @map("impact_i") + impactA Int @default(0) @map("impact_a") + // Dringlichkeit (0–4) — zweite Achse der Severity-Matrix (§5, src/lib/incident-severity.ts). + urgency Int @default(2) + affectedDataCategories String[] @default([]) @map("affected_data_categories") + personalData Boolean @default(false) @map("personal_data") // → dsgvoRelevant + prototypeData Boolean @default(false) @map("prototype_data") // → tisaxFlag + + // Bewertung (§5) — Default-Matrix in Code, hier persistiert (überschreibbar). + severity String @default("mittel") // niedrig | mittel | hoch | kritisch + priority String @default("mittel") // niedrig | mittel | hoch | kritisch + + // Steuerung (§3/§4) + ownerId String? @map("owner_id") + assigneeId String? @map("assignee_id") + status IncidentStatus @default(neu) + restricted Boolean @default(false) // Vertraulichkeit (§11) — nur owner + manage/close + + // Meldepflicht (§6) — Track vorbereitet, Timer-LOGIK erst IM-B. + nis2Relevant Boolean @default(false) @map("nis2_relevant") + dsgvoRelevant Boolean @default(false) @map("dsgvo_relevant") + reportStatus String @default("none") @map("report_status") // none | pruefung | erstmeldung | folgemeldung | abschluss + erstmeldungDueAt DateTime? @map("erstmeldung_due_at") // NIS2 24 h (IM-B) + folgemeldungDueAt DateTime? @map("folgemeldung_due_at") // NIS2 72 h + abschlussDueAt DateTime? @map("abschluss_due_at") // NIS2 1 Monat + dsgvoDueAt DateTime? @map("dsgvo_due_at") // DSGVO Art. 33 72 h + + // Behebung & Abschluss (§8) + rootCause String? @map("root_cause") + resolution String? + closingNote String? @map("closing_note") + lessonsLearned String? @map("lessons_learned") + // §8 IM-C: Wirksamkeit der (CAPA-)Maßnahmen + optionaler Post-Incident-Review + // (Kurzbericht) — speist das Management-Review (als Feld/Notiz, da kein + // eigenständiges Review-Modul). + measuresEffectiveness String? @map("measures_effectiveness") + postIncidentReview String? @map("post_incident_review") + + createdBy String? @map("created_by") + // IM-D — Inbound: Message-ID der Quell-Mail (Idempotenz gegen Doppel-Ticket beim + // erneuten Abholen derselben Mail). Nur bei source=email gesetzt. + inboundMessageId String? @map("inbound_message_id") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + owner User? @relation("incidentOwner", fields: [ownerId], references: [id]) + assignee User? @relation("incidentAssignee", fields: [assigneeId], references: [id]) + + comments IncidentComment[] + incidentAssets IncidentAsset[] + incidentProcesses IncidentProcess[] + incidentRisks IncidentRisk[] + incidentControls IncidentControl[] + incidentMeasures IncidentMeasure[] + incidentEvidence IncidentEvidence[] + attachments IncidentAttachment[] + + @@unique([tenantId, refNo]) + @@index([tenantId]) + @@index([tenantId, status]) + @@index([tenantId, severity]) + @@index([inboundMessageId]) + @@map("incidents") +} + +// Kommentar-Thread am Vorfall (§4) — Zusammenarbeit, getrennt von der Audit-Timeline. +model IncidentComment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + authorId String? @map("author_id") + body String + internal Boolean @default(false) // interner vs. sichtbarer Kommentar + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + + @@index([tenantId, incidentId]) + @@map("incident_comments") +} + +// Betroffenheit: verknüpfte Assets (n:m, Muster RiskAsset). +model IncidentAsset { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + assetId String @map("asset_id") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade) + + @@unique([incidentId, assetId]) + @@index([tenantId]) + @@map("incident_assets") +} + +// Betroffenheit: verknüpfte Prozesse (BIA). +model IncidentProcess { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + processId String @map("process_id") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + process Process @relation(fields: [processId], references: [id], onDelete: Cascade) + + @@unique([incidentId, processId]) + @@index([tenantId]) + @@map("incident_processes") +} + +// Verknüpfte Risiken (bestätigt/neu). +model IncidentRisk { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + riskId String @map("risk_id") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + risk Risk @relation(fields: [riskId], references: [id], onDelete: Cascade) + + @@unique([incidentId, riskId]) + @@index([tenantId]) + @@map("incident_risks") +} + +// Betroffene/versagte Controls — als Katalog-Referenz (kein FK, ISA-Control-Ref). +model IncidentControl { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + controlRef String @map("control_ref") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + + @@unique([incidentId, controlRef]) + @@index([tenantId]) + @@map("incident_controls") +} + +// Verknüpfung zum zentralen Maßnahmen-Modul (§9) — Detailausbau IM-C. +model IncidentMeasure { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + measureId String @map("measure_id") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + measure Measure @relation(fields: [measureId], references: [id], onDelete: Cascade) + + @@unique([incidentId, measureId]) + @@index([tenantId]) + @@map("incident_measures") +} + +// Verknüpfte Nachweise (§9, IM-C) — Beweissicherung (ISO A.5.28). Referenziert das +// zentrale Evidence-Modell; optionaler Kontext-Vermerk je Verknüpfung. +model IncidentEvidence { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + evidenceId String @map("evidence_id") + note String? + + createdAt DateTime @default(now()) @map("created_at") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + evidence Evidence @relation(fields: [evidenceId], references: [id], onDelete: Cascade) + + @@unique([incidentId, evidenceId]) + @@index([tenantId]) + @@map("incident_evidence") +} + +// Anhänge (§4) — Modell VORBEREITET, KEINE Datei-Persistenz (Storage-Paket später). +model IncidentAttachment { + id String @id @default(cuid()) + tenantId String @map("tenant_id") + incidentId String @map("incident_id") + name String + storageKey String? @map("storage_key") + size Int? + mime String? + + createdAt DateTime @default(now()) @map("created_at") + + incident Incident @relation(fields: [incidentId], references: [id], onDelete: Cascade) + + @@index([tenantId, incidentId]) + @@map("incident_attachments") +} + +// IM-D — E-Mail-to-Ticket (Inbound). Mandantenspezifische Intake-Konfiguration: +// je Mandant genau EINE Zeile mit einem global eindeutigen, nicht erratbaren +// `token`. Daraus wird die Intake-Adresse `vorfall-<token>@in.certvia.de` +// abgeleitet (Domain aus Env INCIDENT_INTAKE_DOMAIN, Default in.certvia.de) — +// die Adresse ist NICHT gespeichert, sondern wird aus token+Domain berechnet +// (eine Quelle). Mandantengebunden → RLS + in TENANT_MODELS. +model IncidentIntakeConfig { + id String @id @default(cuid()) + tenantId String @unique @map("tenant_id") + // Global eindeutig (Catch-all + Auto-Token, KONZEPT §2/§12a): der Token trägt die + // Mandantenzuordnung, daher UNIQUE über alle Mandanten. + token String @unique + // Absender-/Weiterleitungs-Domänen des Kunden (Allowlist, KONZEPT §2/§12a). + allowlistDomains String[] @default([]) @map("allowlist_domains") + // Optionale konkrete Quelladresse (vorfall@kunde.de), von der weitergeleitet wird. + sourceAddress String? @map("source_address") + // Provisionierungs-Status je Kunde (vereinfachte Variante, §12a): + // weiterleitung_ausstehend → verifiziert (per Test-Mail). + status String @default("weiterleitung_ausstehend") + verifiedAt DateTime? @map("verified_at") + // Benachrichtigungsempfänger/Sprache (optional) für Inbound-Ereignisse. + notifyEmail String? @map("notify_email") + notifyLocale String @default("de") @map("notify_locale") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@map("incident_intake_config") +} + +// IM-D — Betreiber-Review-Warteschlange für Inbound-Mails ohne/unbekannten Token +// oder mit Allowlist-Fehlschlag. Bewusst PLATTFORM-weit (tenant-los, KEINE RLS, +// NICHT in TENANT_MODELS): der Betreiber sichtet diese Mails mandantenübergreifend +// statt sie zu verwerfen (KONZEPT §2 „unbekannter/kein Token → Betreiber-Review"). +model IncidentInboundReview { + id String @id @default(cuid()) + // Message-ID (Idempotenz/Dedupe). Wird auch als Dublettenschutz gelesen. + messageId String? @map("message_id") + sender String + subject String? + // Empfänger-Header (Delivered-To/X-Envelope-To), aus dem der Token gezogen wurde. + recipient String? + // Geparster Token, falls vorhanden aber unbekannt. + token String? + // Grund: no_token | unknown_token | allowlist_failed | dkim_failed + reason String + // offen | erledigt | zugeordnet + status String @default("offen") + // Optional: aufgelöster Mandant (Token bekannt, aber Allowlist/DKIM scheiterte). + tenantId String? @map("tenant_id") + receivedAt DateTime @map("received_at") + createdAt DateTime @default(now()) @map("created_at") + + @@index([status]) + @@index([messageId]) + @@map("incident_inbound_review") +} diff --git a/prisma/seed-content.ts b/prisma/seed-content.ts new file mode 100644 index 0000000..5664078 --- /dev/null +++ b/prisma/seed-content.ts @@ -0,0 +1,60 @@ +import "dotenv/config"; +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { pathToFileURL } from "node:url"; +import { CONTROL_DOMAIN_DEFAULTS } from "../src/lib/control-domain"; +import { importProcessCatalog } from "./import-process-catalog"; + +/** + * Prod-tauglicher Content-Seed: die GLOBALEN, mandantenunabhängigen Inhalte der + * TISAX-Neustruktur — Control→Domain/RACI-Defaults (M3) und Prozess-Katalog (M2). + * Enthält KEINE Demo-/Mandantendaten und ist idempotent (upsert bzw. + * global-neu-setzen), also gefahrlos in jeder Umgebung mehrfach ausführbar. + * + * Wird vom Demo-Seed (`seed.ts`) wiederverwendet und ist eigenständig ausführbar: + * npm run seed:content + */ +export async function seedGlobalContent( + prisma: PrismaClient +): Promise<{ controlDomains: number; processCatalog: number }> { + // Control→Domain/RACI-Defaults (global, tenantId = null). Idempotent: die globalen + // Zeilen werden neu gesetzt; mandantenspezifische Overrides (tenantId != null) bleiben. + await prisma.controlDomainMap.deleteMany({ where: { tenantId: null } }); + await prisma.controlDomainMap.createMany({ + data: CONTROL_DOMAIN_DEFAULTS.map((r) => ({ + tenantId: null, + control: r.control, + domain: r.domain, + raci: r.raci, + functionKey: r.functionKey ?? null, + })), + }); + + // Prozess-Katalog (global, upsert je code — idempotent). + const processCatalog = await importProcessCatalog(prisma); + + return { controlDomains: CONTROL_DOMAIN_DEFAULTS.length, processCatalog }; +} + +async function main() { + const prisma = new PrismaClient({ + adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), + }); + try { + console.log("→ Globaler Content-Seed (Control→Domain-Defaults + Prozess-Katalog)…"); + const { controlDomains, processCatalog } = await seedGlobalContent(prisma); + console.log(`✔ ${controlDomains} Control→Domain-Defaults`); + console.log(`✔ ${processCatalog} Prozess-Katalog-Einträge`); + console.log("✓ Globaler Content-Seed abgeschlossen."); + } finally { + await prisma.$disconnect(); + } +} + +// Nur als eigenständiger Runner ausführen, nicht beim Import aus seed.ts. +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + main().catch((e) => { + console.error(e); + process.exit(1); + }); +} diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..be7cecd --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,739 @@ +import "dotenv/config"; +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { hashPassword } from "../src/server/password"; +import { join } from "node:path"; +import { PERMISSIONS, ROLE_DEFS } from "../src/server/rbac"; +import { importPolicies, stampPackageState } from "./import-policies"; +import { importImplementationHints } from "./import-hints"; +import { importRiskCatalog } from "./import-risks"; +import { seedGlobalContent } from "./seed-content"; +import { importManaged } from "./import-managed"; +import { MODULE_KEYS } from "../src/lib/modules"; +import { normalizeAssetName } from "../src/lib/normalize-asset"; +import { provisionTenant } from "../src/server/provision"; + +/** + * Seed: global permission catalog + demo tenant with roles and users. + * Idempotent (upserts) — safe to run repeatedly. + */ + +const prisma = new PrismaClient({ + adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), +}); + +const DEMO_PASSWORD = "Demo1234!"; + +const THREATS = [ + "Schadsoftware / Ransomware", + "Phishing / Social Engineering", + "Innentäter / Missbrauch von Berechtigungen", + "Diebstahl oder Verlust von Geräten", + "Ausfall von IT-Systemen oder Diensten", + "Ausfall eines Dienstleisters / Lieferanten", + "Stromausfall / Infrastrukturausfall", + "Feuer / Wasser / Elementarschäden", + "Unbefugter physischer Zutritt", + "Denial-of-Service-Angriff", + "Datenabfluss / Industriespionage", + "Fehlbedienung durch Mitarbeitende", + "Softwarefehler / fehlerhafte Updates", + "Kompromittierte Zugangsdaten", + "Rechtliche / regulatorische Verstöße", +]; + +const VULNERABILITIES = [ + "Fehlende oder veraltete Backups", + "Fehlende Netzwerksegmentierung", + "Unzureichendes Patch-Management", + "Schwache oder wiederverwendete Passwörter", + "Fehlende Multi-Faktor-Authentifizierung", + "Übermäßige Berechtigungen / fehlendes Least-Privilege", + "Fehlende Awareness / Schulungen", + "Unverschlüsselte Datenträger oder Übertragungen", + "Kein Notfallkonzept / ungetesteter Wiederanlauf", + "Single Point of Failure (Technik oder Person)", + "Unzureichende Protokollierung / Überwachung", + "Veraltete oder nicht mehr unterstützte Software", + "Fehlende Vertrags-/AV-Regelungen mit Dienstleistern", + "Offene, ungenutzte Dienste und Ports", + "Unklare Verantwortlichkeiten", +]; + +async function main() { + // 0. Globale Kataloge Bedrohungen/Schwachstellen (Vorschläge, Freitext bleibt möglich) + for (const name of THREATS) { + await prisma.threat.upsert({ where: { name }, update: {}, create: { name } }); + } + for (const name of VULNERABILITIES) { + await prisma.vulnerability.upsert({ where: { name }, update: {}, create: { name } }); + } + console.log(`✔ Kataloge: ${THREATS.length} Bedrohungen, ${VULNERABILITIES.length} Schwachstellen`); + + // 1. Global permission catalog + for (const key of PERMISSIONS) { + await prisma.permission.upsert({ where: { key }, update: {}, create: { key } }); + } + console.log(`✔ ${PERMISSIONS.length} Permissions`); + + // 1b. Globaler Content (M2/M3): Control→Domain/RACI-Defaults + Prozess-Katalog. + // Ausgelagert in den prod-tauglichen, idempotenten Content-Seed (seed-content.ts), + // damit DevOps ihn auch ohne Demo-Seed in jeder Umgebung fahren kann (npm run seed:content). + const globalContent = await seedGlobalContent(prisma); + console.log(`✔ ${globalContent.controlDomains} Control→Domain-Defaults (M3)`); + + // 2. Demo tenant + const tenant = await prisma.tenant.upsert({ + where: { slug: "demo" }, + update: {}, + create: { name: "Demo GmbH", slug: "demo" }, + }); + + // 3. Roles from blueprints, with permission bundles + for (const [key, def] of Object.entries(ROLE_DEFS)) { + const role = await prisma.role.upsert({ + where: { tenantId_key: { tenantId: tenant.id, key } }, + update: { name: def.name }, + create: { tenantId: tenant.id, key, name: def.name }, + }); + const perms = await prisma.permission.findMany({ + where: { key: { in: [...def.permissions] } }, + }); + for (const p of perms) { + await prisma.rolePermission.upsert({ + where: { roleId_permissionId: { roleId: role.id, permissionId: p.id } }, + update: {}, + create: { roleId: role.id, permissionId: p.id }, + }); + } + } + console.log(`✔ Mandant "demo" mit ${Object.keys(ROLE_DEFS).length} Rollen`); + + // 4. Demo users + const passwordHash = await hashPassword(DEMO_PASSWORD); + const demoUsers: { email: string; name: string; roles: string[] }[] = [ + { email: "admin@demo.example", name: "Anna Admin", roles: ["tenant-admin", "isb"] }, + // Zweiter ISB als Freigeber — ermöglicht den Vier-Augen-Freigabe-Workflow (≠ Einreicher). + { email: "bea.approver@demo.example", name: "Bea Approver", roles: ["isb"] }, + { email: "auditor@demo.example", name: "Axel Auditor", roles: ["auditor"] }, + { email: "owner@demo.example", name: "Oskar Owner", roles: ["owner"] }, + { email: "user@demo.example", name: "Ulla User", roles: ["user"] }, + ]; + + for (const u of demoUsers) { + // Option C: globale Identity (Anmeldung) + Mitgliedschaft (User) im Mandanten. + // Diese 5 Standard-Logins bleiben bewusst SINGLE-Membership, damit der + // (bis WS1) einstufige Login-Lookup (auth.ts: findMany by email) eindeutig + // bleibt und dev lauffähig ist. Der Multi-Membership-Fall wird über einen + // separaten Fixture-Nutzer (multi@demo.example) abgebildet (siehe unten). + const idn = await prisma.identity.upsert({ + where: { email: u.email }, + update: {}, + create: { email: u.email, passwordHash }, + }); + const user = await prisma.user.upsert({ + where: { tenantId_email: { tenantId: tenant.id, email: u.email } }, + update: { identityId: idn.id }, + create: { + tenantId: tenant.id, + identityId: idn.id, + email: u.email, + name: u.name, + }, + }); + const roles = await prisma.role.findMany({ + where: { tenantId: tenant.id, key: { in: u.roles } }, + }); + for (const r of roles) { + await prisma.userRole.upsert({ + where: { userId_roleId: { userId: user.id, roleId: r.id } }, + update: {}, + create: { userId: user.id, roleId: r.id }, + }); + } + } + console.log(`✔ ${demoUsers.length} Demo-Nutzer (Passwort: ${DEMO_PASSWORD})`); + + // 4b. Zweiter Mandant + Multi-Membership-Fixture (Option C, WS0/WS2/WS7). + // Eine Identity (multi@demo.example) ist Mitglied in ZWEI Mandanten mit je + // unterschiedlichen Rollen — Grundlage für Tenant-Switch- und Isolationstests. + // `demo2` wird schlank provisioniert (Rollen/Module/Einstellungen, ohne + // Richtlinienpaket). Berührt die 5 Standard-Logins nicht. + const tenant2 = await provisionTenant(prisma, { + name: "Demo Zwei GmbH", + slug: "demo2", + short: "Demo2", + sector: "Automotive", + admin: { email: "admin2@demo.example", name: "Zoe Zweitadmin", password: DEMO_PASSWORD }, + }); + const multiIdentity = await prisma.identity.upsert({ + where: { email: "multi@demo.example" }, + update: {}, + create: { email: "multi@demo.example", passwordHash }, + }); + // Mitgliedschaft je Mandant mit je eigener Rolle (Rechte je aktivem Mandant verschieden). + const multiMemberships: { tenantId: string; roleKey: string }[] = [ + { tenantId: tenant.id, roleKey: "user" }, // in "demo": nur Standardnutzer + { tenantId: tenant2.id, roleKey: "tenant-admin" }, // in "demo2": Mandanten-Admin + ]; + for (const m of multiMemberships) { + const membership = await prisma.user.upsert({ + where: { tenantId_email: { tenantId: m.tenantId, email: "multi@demo.example" } }, + update: { identityId: multiIdentity.id }, + create: { + tenantId: m.tenantId, + identityId: multiIdentity.id, + email: "multi@demo.example", + name: "Mika Multi", + }, + }); + const role = await prisma.role.findFirst({ where: { tenantId: m.tenantId, key: m.roleKey } }); + if (role) { + await prisma.userRole.upsert({ + where: { userId_roleId: { userId: membership.id, roleId: role.id } }, + update: {}, + create: { userId: membership.id, roleId: role.id }, + }); + } + } + console.log(`✔ Multi-Membership-Fixture multi@demo.example (Mandanten: demo, demo2)`); + + // 5. Beispiel-Assets, -Prozesse und BIA (nur wenn noch keine Assets existieren) + const assetCount = await prisma.asset.count({ where: { tenantId: tenant.id } }); + if (assetCount === 0) { + const isb = await prisma.user.findUniqueOrThrow({ + where: { tenantId_email: { tenantId: tenant.id, email: "admin@demo.example" } }, + }); + const owner = await prisma.user.findUniqueOrThrow({ + where: { tenantId_email: { tenantId: tenant.id, email: "owner@demo.example" } }, + }); + + const mk = (data: { + name: string; + type: "INFORMATION" | "SYSTEM" | "APPLICATION" | "LOCATION" | "SUPPLIER" | "PERSON" | "DATA"; + c: number; + i: number; + a: number; + ownerId?: string; + location?: string; + tags?: string[]; + description?: string; + }) => + prisma.asset.create({ + data: { + tenantId: tenant.id, + name: data.name, + type: data.type, + // M2: Dedup-Schlüssel setzen (nur INFORMATION/DATA sind primäre Werte; + // für die übrigen Typen dient er nur der Exakt-Duplikat-Vermeidung). + normalizedName: normalizeAssetName(data.name), + confidentiality: data.c, + integrity: data.i, + availability: data.a, + ownerId: data.ownerId, + location: data.location, + tags: data.tags ?? [], + description: data.description, + }, + }); + + const erp = await mk({ name: "ERP-System", type: "SYSTEM", c: 3, i: 4, a: 3, ownerId: owner.id, location: "RZ Frankfurt", tags: ["kritisch", "kern"] }); + const crm = await mk({ name: "Kundendatenbank", type: "DATA", c: 4, i: 3, a: 2, ownerId: isb.id, tags: ["dsgvo"] }); + const auftraege = await mk({ name: "Auftragsdaten", type: "INFORMATION", c: 3, i: 4, a: 3, ownerId: owner.id }); + const hoster = await mk({ name: "Cloud-Hoster (IaaS)", type: "SUPPLIER", c: 2, i: 3, a: 4, description: "Betreibt das Rechenzentrum für ERP und CRM." }); + const buero = await mk({ name: "Bürostandort München", type: "LOCATION", c: 2, i: 2, a: 2 }); + const itTeam = await mk({ name: "IT-Administration", type: "PERSON", c: 3, i: 3, a: 3 }); + + await prisma.assetRelation.createMany({ + data: [ + { tenantId: tenant.id, assetId: erp.id, relatedAssetId: hoster.id, type: "depends_on" }, + { tenantId: tenant.id, assetId: crm.id, relatedAssetId: hoster.id, type: "depends_on" }, + { tenantId: tenant.id, assetId: erp.id, relatedAssetId: itTeam.id, type: "depends_on" }, + ], + }); + + const auftrag = await prisma.process.create({ + data: { + tenantId: tenant.id, + name: "Auftragsabwicklung", + description: "Vom Kundenauftrag bis zur Auslieferung.", + category: "CORE", + ownerId: owner.id, + }, + }); + await prisma.processAsset.createMany({ + data: [ + { tenantId: tenant.id, processId: auftrag.id, assetId: auftraege.id, role: "PRIMARY" }, + { tenantId: tenant.id, processId: auftrag.id, assetId: erp.id, role: "SECONDARY" }, + { tenantId: tenant.id, processId: auftrag.id, assetId: crm.id, role: "SECONDARY" }, + { tenantId: tenant.id, processId: auftrag.id, assetId: itTeam.id, role: "SECONDARY" }, + ], + }); + await prisma.biaEntry.create({ + data: { + tenantId: tenant.id, + processId: auftrag.id, + rtoHours: 8, + rpoHours: 4, + mtdHours: 24, + impactC: 2, + impactI: 4, + impactA: 3, + criticality: 4, + notes: "Ausfall > 1 Tag führt zu Lieferverzug und Vertragsstrafen.", + }, + }); + + const vertrieb = await prisma.process.create({ + data: { + tenantId: tenant.id, + name: "Kundenbetreuung", + description: "Anfragen, Angebote, Support.", + category: "SUPPORT", + ownerId: isb.id, + }, + }); + await prisma.processAsset.createMany({ + data: [ + { tenantId: tenant.id, processId: vertrieb.id, assetId: crm.id, role: "PRIMARY" }, + { tenantId: tenant.id, processId: vertrieb.id, assetId: buero.id, role: "SECONDARY" }, + ], + }); + await prisma.biaEntry.create({ + data: { + tenantId: tenant.id, + processId: vertrieb.id, + rtoHours: 24, + rpoHours: 24, + mtdHours: 72, + impactC: 3, + impactI: 2, + impactA: 2, + criticality: 3, + notes: "Kundenkommunikation kann kurzfristig über Ausweichkanäle laufen.", + }, + }); + + console.log("✔ Beispiel-Assets, -Prozesse und BIA angelegt"); + } + + // 6. Beispiel-Risiken (nur wenn noch keine existieren) + const riskCount = await prisma.risk.count({ where: { tenantId: tenant.id } }); + if (riskCount === 0) { + const isb = await prisma.user.findUniqueOrThrow({ + where: { tenantId_email: { tenantId: tenant.id, email: "admin@demo.example" } }, + }); + const byName = async (name: string) => + prisma.asset.findFirstOrThrow({ where: { tenantId: tenant.id, name } }); + const erp = await byName("ERP-System"); + const crm = await byName("Kundendatenbank"); + const hoster = await byName("Cloud-Hoster (IaaS)"); + const auftrag = await prisma.process.findFirstOrThrow({ + where: { tenantId: tenant.id, name: "Auftragsabwicklung" }, + }); + + const risks: { + title: string; + threat: string; + vulnerability: string; + likelihood: number; + impact: number; + residual?: [number, number]; + treatment: "AVOID" | "MITIGATE" | "TRANSFER" | "ACCEPT"; + status: "OPEN" | "IN_TREATMENT" | "ACCEPTED" | "CLOSED"; + assets: string[]; + processId?: string; + description?: string; + }[] = [ + { + title: "Ransomware auf ERP", + threat: "Schadsoftware / Verschlüsselungstrojaner", + vulnerability: "Fehlende Offline-Backups, Makro-Ausführung erlaubt", + likelihood: 4, + impact: 5, + residual: [2, 4], + treatment: "MITIGATE", + status: "IN_TREATMENT", + assets: [erp.id, crm.id], + processId: auftrag.id, + description: "Verschlüsselung der ERP-Datenbank würde die Auftragsabwicklung stoppen.", + }, + { + title: "Ausfall Cloud-Hoster", + threat: "Ausfall des Rechenzentrums / Insolvenz Dienstleister", + vulnerability: "Kein Ausweich-Standort, Single Provider", + likelihood: 4, + impact: 4, + treatment: "TRANSFER", + status: "OPEN", + assets: [hoster.id, erp.id], + processId: auftrag.id, + }, + { + title: "Phishing / Social Engineering", + threat: "Gezielte Phishing-Kampagnen", + vulnerability: "Fehlende Awareness-Schulungen", + likelihood: 3, + impact: 3, + residual: [2, 3], + treatment: "MITIGATE", + status: "IN_TREATMENT", + assets: [crm.id], + }, + { + title: "Verlust mobiler Geräte", + threat: "Diebstahl/Verlust von Notebooks", + vulnerability: "Unvollständige Festplattenverschlüsselung", + likelihood: 2, + impact: 3, + treatment: "ACCEPT", + status: "ACCEPTED", + assets: [], + }, + ]; + + let refNo = 1; + for (const r of risks) { + const risk = await prisma.risk.create({ + data: { + tenantId: tenant.id, + refNo: refNo++, + title: r.title, + description: r.description, + threat: r.threat, + vulnerability: r.vulnerability, + likelihood: r.likelihood, + impact: r.impact, + score: r.likelihood * r.impact, + residualLikelihood: r.residual?.[0], + residualImpact: r.residual?.[1], + residualScore: r.residual ? r.residual[0] * r.residual[1] : undefined, + treatment: r.treatment, + status: r.status, + ownerId: isb.id, + processId: r.processId, + }, + }); + for (const assetId of r.assets) { + await prisma.riskAsset.create({ + data: { tenantId: tenant.id, riskId: risk.id, assetId }, + }); + } + } + console.log(`✔ ${risks.length} Beispiel-Risiken angelegt`); + } + + // 7. Beispiel-Maßnahmen (nur wenn noch keine existieren) — bestimmen das Rest-Risiko + const measureCount = await prisma.measure.count({ where: { tenantId: tenant.id } }); + if (measureCount === 0) { + const owner = await prisma.user.findUniqueOrThrow({ + where: { tenantId_email: { tenantId: tenant.id, email: "owner@demo.example" } }, + }); + const riskByTitle = (title: string) => + prisma.risk.findFirst({ where: { tenantId: tenant.id, title } }); + + const measures: { + title: string; + status: "OPEN" | "IN_PROGRESS" | "DONE"; + priority: "LOW" | "MEDIUM" | "HIGH"; + dueInDays?: number; + riskTitle?: string; + reduction?: [number, number]; // [Wahrscheinlichkeit, Schaden] + }[] = [ + { + title: "Offline-Backups einführen (3-2-1-Regel)", + status: "IN_PROGRESS", + priority: "HIGH", + dueInDays: 14, + riskTitle: "Ransomware auf ERP", + reduction: [1, 1], + }, + { + title: "Makro-Ausführung per GPO einschränken", + status: "OPEN", + priority: "HIGH", + dueInDays: 30, + riskTitle: "Ransomware auf ERP", + reduction: [1, 0], + }, + { + title: "Awareness-Schulung Phishing (alle Mitarbeitenden)", + status: "IN_PROGRESS", + priority: "MEDIUM", + dueInDays: 45, + riskTitle: "Phishing / Social Engineering", + reduction: [1, 0], + }, + { + title: "Notfallhandbuch aktualisieren", + status: "DONE", + priority: "MEDIUM", + }, + ]; + + let mRef = 1; + for (const m of measures) { + const measure = await prisma.measure.create({ + data: { + tenantId: tenant.id, + refNo: mRef++, + title: m.title, + status: m.status, + priority: m.priority, + ownerId: owner.id, + dueDate: m.dueInDays + ? new Date(Date.now() + m.dueInDays * 24 * 3600 * 1000) + : undefined, + }, + }); + if (m.riskTitle && m.reduction) { + const risk = await riskByTitle(m.riskTitle); + if (risk) { + await prisma.riskMeasure.create({ + data: { + tenantId: tenant.id, + riskId: risk.id, + measureId: measure.id, + reductionLikelihood: m.reduction[0], + reductionImpact: m.reduction[1], + }, + }); + } + } + } + + // Rest-Risiken aus den Maßnahmen ableiten (manuelle Alt-Werte ersetzen) + const allRisks = await prisma.risk.findMany({ + where: { tenantId: tenant.id }, + include: { riskMeasures: true }, + }); + for (const r of allRisks) { + if (r.riskMeasures.length === 0) { + await prisma.risk.update({ + where: { id: r.id }, + data: { residualLikelihood: null, residualImpact: null, residualScore: null }, + }); + } else { + const redL = r.riskMeasures.reduce((s, x) => s + x.reductionLikelihood, 0); + const redI = r.riskMeasures.reduce((s, x) => s + x.reductionImpact, 0); + const rl = Math.max(1, r.likelihood - redL); + const ri = Math.max(1, r.impact - redI); + await prisma.risk.update({ + where: { id: r.id }, + data: { residualLikelihood: rl, residualImpact: ri, residualScore: rl * ri }, + }); + } + } + console.log(`✔ ${measures.length} Beispiel-Maßnahmen angelegt, Rest-Risiken berechnet`); + } + + // 8. Demo-Lieferanten als Assets (type SUPPLIER) mit Profil, Nachweisen, Verträgen + const supCount = await prisma.supplierProfile.count({ where: { tenantId: tenant.id } }); + if (supCount === 0) { + const hoster = await prisma.asset.findFirst({ where: { tenantId: tenant.id, name: "Cloud-Hoster (IaaS)" } }); + + const a1 = await prisma.asset.create({ + data: { tenantId: tenant.id, name: "Cloud-Hoster GmbH", type: "SUPPLIER", confidentiality: 3, integrity: 3, availability: 4 }, + }); + await prisma.supplierProfile.create({ + data: { tenantId: tenant.id, assetId: a1.id, refNo: 1, sector: "IT-Dienstleistung / IaaS", serviceDesc: "Rechenzentrum, Virtualisierung, Backup", criticality: 4, dataCategories: ["Kundendaten", "Auftragsdaten"], nis2Relevant: true, lifecycle: "ACTIVE", contact: "security@cloud-hoster.example", nextReview: new Date(Date.now() + 90 * 24 * 3600 * 1000) }, + }); + if (hoster) await prisma.assetRelation.create({ data: { tenantId: tenant.id, assetId: a1.id, relatedAssetId: hoster.id, type: "provides" } }).catch(() => {}); + await prisma.supplierEvidence.create({ data: { tenantId: tenant.id, assetId: a1.id, kind: "TISAX_LABEL", name: "TISAX AL3 (info high)", protectsCia: "C,I,A", validTo: new Date(Date.now() + 200 * 24 * 3600 * 1000), adequacyChecked: true } }); + await prisma.contract.create({ data: { tenantId: tenant.id, assetId: a1.id, type: "av_dpa", avDpa: true, securityClauses: true, flowdown: true, customerRequirementsPassed: true, validTo: new Date(Date.now() + 400 * 24 * 3600 * 1000), reference: "AV-2025-014" } }); + await prisma.nda.create({ data: { tenantId: tenant.id, assetId: a1.id, subject: "Betrieb der ERP-/CRM-Infrastruktur", parties: "Demo GmbH / Cloud-Hoster GmbH", validTo: new Date(Date.now() + 60 * 24 * 3600 * 1000), extensionStatus: "offen" } }); + await prisma.supplierAssessment.create({ data: { tenantId: tenant.id, assetId: a1.id, type: "SELF_ASSESSMENT", score: 82, date: new Date(Date.now() - 120 * 24 * 3600 * 1000), nextReview: new Date(Date.now() + 245 * 24 * 3600 * 1000), result: "angemessen" } }); + + const a2 = await prisma.asset.create({ + data: { tenantId: tenant.id, name: "WebAgentur X", type: "SUPPLIER", confidentiality: 2, integrity: 2, availability: 2 }, + }); + await prisma.supplierProfile.create({ + data: { tenantId: tenant.id, assetId: a2.id, refNo: 2, sector: "Webentwicklung", serviceDesc: "Website-Betrieb", criticality: 2, dataCategories: ["Marketingdaten"], nis2Relevant: false, lifecycle: "UNDER_REVIEW" }, + }); + + console.log("✔ 2 Demo-Lieferanten als Assets angelegt"); + } + + // 9. Demo-IT-Service (type IT_SERVICE) mit RACI-Matrix über den ISA-Katalog + const svcCount = await prisma.iTServiceProfile.count({ where: { tenantId: tenant.id } }); + if (svcCount === 0) { + const provider = await prisma.asset.findFirst({ where: { tenantId: tenant.id, name: "Cloud-Hoster GmbH", type: "SUPPLIER" } }); + const svc = await prisma.asset.create({ + data: { tenantId: tenant.id, name: "Managed ERP-Hosting", type: "IT_SERVICE", confidentiality: 3, integrity: 3, availability: 4 }, + }); + await prisma.iTServiceProfile.create({ + data: { tenantId: tenant.id, assetId: svc.id, refNo: 1, criticality: 4, internal: false, providerAssetId: provider?.id ?? null, notes: "Betrieb & Wartung der ERP-Plattform beim Cloud-Hoster (Shared Responsibility)." }, + }); + const raci: { controlRef: string; title: string; responsibility: "PROVIDER" | "US" | "SHARED"; evidenceRef?: string }[] = [ + { controlRef: "4.1.2", title: "Authentisierung / MFA", responsibility: "SHARED", evidenceRef: "IAM-Konzept v2" }, + { controlRef: "5.2.4", title: "Schwachstellen-/Patch-Management", responsibility: "PROVIDER", evidenceRef: "Patch-SLA" }, + { controlRef: "5.2.5", title: "Datensicherung / Backup", responsibility: "PROVIDER", evidenceRef: "Backup-Report Q2" }, + { controlRef: "4.1.3", title: "Zugriffsrechte-Verwaltung", responsibility: "US" }, + { controlRef: "1.6.1", title: "Informationssicherheits-Vorfälle", responsibility: "SHARED", evidenceRef: "IR-Runbook" }, + ]; + for (const r of raci) { + await prisma.serviceControlResponsibility.create({ + data: { tenantId: tenant.id, assetId: svc.id, controlRef: r.controlRef, title: r.title, applicable: true, responsibility: r.responsibility, evidenceRef: r.evidenceRef ?? null }, + }); + } + console.log("✔ 1 Demo-IT-Service mit RACI-Matrix angelegt"); + } + + // 9b. Demo-Vorfälle (Modul „Vorfälle", IM-A) — 1–2 Beispiele im Demo-Mandanten + const incidentCount = await prisma.incident.count({ where: { tenantId: tenant.id } }); + if (incidentCount === 0) { + const isb = await prisma.user.findUnique({ + where: { tenantId_email: { tenantId: tenant.id, email: "admin@demo.example" } }, + }); + const owner = await prisma.user.findUnique({ + where: { tenantId_email: { tenantId: tenant.id, email: "owner@demo.example" } }, + }); + const crm = await prisma.asset.findFirst({ where: { tenantId: tenant.id, name: "Kundendatenbank" } }); + const erp = await prisma.asset.findFirst({ where: { tenantId: tenant.id, name: "ERP-System" } }); + const vertrieb = await prisma.process.findFirst({ where: { tenantId: tenant.id, name: "Kundenbetreuung" } }); + const year = new Date().getFullYear(); + + // Vorfall 1: Phishing (mittlerer Schweregrad), in Bearbeitung, mit betroffenem Asset/Prozess. + const inc1 = await prisma.incident.create({ + data: { + tenantId: tenant.id, + refNo: `INC-${year}-0001`, + title: "Phishing-Welle gegen Vertriebsmitarbeitende", + description: "Mehrere Mitarbeitende meldeten gefälschte E-Mails mit Login-Aufforderung. Ein Konto könnte kompromittiert sein.", + source: "manual", + reporterName: "Helpdesk", + reporterContact: "helpdesk@demo.example", + detectedAt: new Date(Date.now() - 2 * 24 * 3600 * 1000), + occurredAt: new Date(Date.now() - 3 * 24 * 3600 * 1000), + reportedAt: new Date(Date.now() - 2 * 24 * 3600 * 1000), + category: "phishing", + impactC: 3, + impactI: 1, + impactA: 0, + urgency: 3, + severity: "hoch", + priority: "hoch", + personalData: true, + dsgvoRelevant: true, + nis2Relevant: false, + status: "in_bearbeitung", + ownerId: isb?.id ?? null, + assigneeId: owner?.id ?? null, + createdBy: isb?.id ?? null, + }, + }); + if (crm) await prisma.incidentAsset.create({ data: { tenantId: tenant.id, incidentId: inc1.id, assetId: crm.id } }); + if (vertrieb) await prisma.incidentProcess.create({ data: { tenantId: tenant.id, incidentId: inc1.id, processId: vertrieb.id } }); + await prisma.incidentComment.create({ + data: { tenantId: tenant.id, incidentId: inc1.id, authorId: isb?.id ?? null, body: "Betroffene Konten gesperrt, Passwort-Reset veranlasst.", internal: false }, + }); + + // Vorfall 2: Kurzer ERP-Ausfall, bereits abgeschlossen (mit Ursache/Lösung/Lessons Learned). + const inc2 = await prisma.incident.create({ + data: { + tenantId: tenant.id, + refNo: `INC-${year}-0002`, + title: "Kurzzeitiger Ausfall des ERP-Systems", + description: "Das ERP-System war rund 40 Minuten nicht erreichbar (Speicherengpass auf dem Applikationsserver).", + source: "manual", + reporterName: "IT-Betrieb", + category: "outage", + impactC: 0, + impactI: 0, + impactA: 3, + urgency: 2, + severity: "mittel", + priority: "mittel", + status: "abgeschlossen", + rootCause: "Fehlende Überwachung des Speicherverbrauchs führte zu einem OOM-Neustart.", + resolution: "Dienst neu gestartet, Speicherlimits angehoben.", + closingNote: "Betrieb nach 40 Minuten wiederhergestellt, kein Datenverlust.", + lessonsLearned: "Monitoring der Ressourcen-Auslastung mit Schwellwert-Alarm einrichten.", + ownerId: isb?.id ?? null, + createdBy: isb?.id ?? null, + }, + }); + if (erp) await prisma.incidentAsset.create({ data: { tenantId: tenant.id, incidentId: inc2.id, assetId: erp.id } }); + + console.log("✔ 2 Demo-Vorfälle angelegt"); + } + + // 10. Richtlinien & Verfahren aus dem VDA-ISA-2027-Vorlagenpaket importieren + // AP1: Framework-Zuordnung des Demo-Mandanten (er wird direkt per upsert angelegt, + // nicht über provisionTenant) — TISAX als Primär-Framework. + await prisma.tenantFramework.upsert({ + where: { tenantId_framework: { tenantId: tenant.id, framework: "TISAX" } }, + update: {}, + create: { tenantId: tenant.id, framework: "TISAX", isPrimary: true }, + }); + const seedDir = join(__dirname, "..", "seed", "isms-vorlagenpaket-v2"); + const pc = await importPolicies(prisma, tenant.id, seedDir); + await stampPackageState(prisma, tenant.id, seedDir); // Story B6: Paket-Version stempeln + // Umsetzungshinweise (C6, Story B5) — globaler Katalog, einmalig/idempotent. + const hintCount = await importImplementationHints(prisma); + // Standard-Risikokatalog (C4, Story A6) — globaler Katalog, einmalig/idempotent. + const riskCatCount = await importRiskCatalog(prisma); + // Standard-Prozess-Katalog (M2) wird bereits oben über seedGlobalContent geseedet. + const processCatCount = globalContent.processCatalog; + // Demo-Werte für Variablen ohne Schema-Default (damit die Doku vollständig wirkt) + const demoVars: Record<string, string> = { + ORG_NAME: "GEFIM Demo GmbH", + ORG_SHORT: "GEFIM", + ISMS_SCOPE: "IT-Betrieb & Softwareentwicklung", + ISMS_SCOPE_DESCRIPTION: "IT-Betrieb, Softwareentwicklung und zugehörige Unterstützungsprozesse am Standort Zentrale", + DOC_DATE: "2026-07-07", + }; + for (const [key, value] of Object.entries(demoVars)) { + await prisma.policyVariable.updateMany({ where: { tenantId: tenant.id, key }, data: { value } }); + } + console.log(`✔ Richtlinienpaket importiert: ${pc.documents} Dokumente, ${pc.requirements} Anforderungen, ${pc.variables} Variablen, ${pc.baseline} Baseline-Parameter`); + console.log(`✔ Umsetzungshinweise (C6) importiert: ${hintCount} Hinweise`); + console.log(`✔ Risikokatalog (C4) importiert: ${riskCatCount} Katalog-Risiken`); + console.log(`✔ Prozess-Katalog (M2) importiert: ${processCatCount} Standard-Prozesse`); + + const mc = await importManaged(prisma, tenant.id); + console.log(`✔ Verwaltete Register: Krypto ${mc.crypto}, Klassifizierung ${mc.classes}×${mc.aspects}, Risikomatrix (${mc.damage} Schadensdim.), Handbuch ${mc.handbook} Themen`); + + // 11. Admin-Konsole: Mandanten-Einstellungen, Module, Plattform-Admin (getrennter Store) + // Demo-Plattform-Admin: gleiche Adresse wie der Mandanten-Admin, damit /login (Mandant) + // und /platform/login (Betrieb) mit denselben Demo-Zugangsdaten funktionieren. MFA wird + // beim ersten Plattform-Login eingerichtet. + await prisma.platformAdmin.upsert({ + where: { email: "admin@demo.example" }, + update: { name: "Anna Admin", status: "ACTIVE" }, + create: { email: "admin@demo.example", name: "Anna Admin", passwordHash: await hashPassword("Demo1234!"), status: "ACTIVE" }, + }); + await prisma.tenantSettings.upsert({ + where: { tenantId: tenant.id }, + update: {}, + create: { + tenantId: tenant.id, + orgName: "GEFIM Demo GmbH", + orgShort: "GEFIM", + sector: "IT-Dienstleistung", + ismsScope: "IT-Betrieb & Softwareentwicklung", + ismsScopeDescription: "IT-Betrieb, Softwareentwicklung und zugehörige Unterstützungsprozesse am Standort Zentrale", + roleManagement: "Geschäftsführung", + roleIsb: "Informationssicherheitsbeauftragte(r) (ISB)", + roleItLead: "IT-Leitung", + roleDpo: "Datenschutzbeauftragte(r) (DSB)", + tisaxLevel: "AL2", + }, + }); + for (const key of MODULE_KEYS) { + await prisma.tenantModule.upsert({ + where: { tenantId_moduleKey: { tenantId: tenant.id, moduleKey: key } }, + update: {}, + create: { tenantId: tenant.id, moduleKey: key, enabled: true }, + }); + } + console.log(`✔ Admin-Konsole: Einstellungen, ${MODULE_KEYS.length} Module aktiv; Plattform-Admin admin@demo.example (getrennter Login /platform/login, MFA beim ersten Login)`); +} + +main() + .then(() => prisma.$disconnect()) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/prisma/template-store.ts b/prisma/template-store.ts new file mode 100644 index 0000000..bcb639e --- /dev/null +++ b/prisma/template-store.ts @@ -0,0 +1,205 @@ +import type { PrismaClient, Framework } from "@prisma/client"; +import type { ParsedPackage, ParsedDoc } from "./import-policies"; +import { parsePackageFiles, readPackageVersion, mappingFileFor } from "./import-policies"; + +/** + * Globale DB-Vorlagenablage (Plattform-Ebene). Master-Quelle für den Mandanten-Import: + * eine `PolicyTemplateVersion` je Paketversion mit Inhalten je Sprache (`locale`). + * + * - `syncTemplatesFromParsed`: schreibt ein `ParsedPackage` (aus den Dateien geparst) + * für eine Sprache in eine Version. Für eine bestehende Version werden die Inhalte + * dieser Sprache vollständig ersetzt (idempotent). Sicher, weil die Vorlagen-Tabellen + * keine Mandanten-/Nutzerdaten enthalten. + * - `loadPublishedPackage`: liest die aktuell veröffentlichte Version in der gewünschten + * Sprache als `ParsedPackage` — dieselbe Struktur wie der Datei-Parser, sodass der + * non-destruktive Mandanten-Reconcile identisch damit arbeitet. Liefert null, wenn es + * keine veröffentlichte Version bzw. keine Inhalte in der Sprache gibt (→ Datei-Fallback). + */ + +type DocType = ParsedDoc["type"]; + +/** Ein Datei-Paket (eine Sprache) in eine Vorlagen-Version schreiben; Inhalte der Sprache ersetzen. */ +export async function syncTemplatesFromParsed( + prisma: PrismaClient, + pkg: ParsedPackage, + locale: string, + framework: Framework = "TISAX", + options: { publish?: boolean; publishedBy?: string | null } = {}, +): Promise<{ versionId: string; version: string }> { + const publish = options.publish ?? true; + // Eindeutigkeit je (Framework, Version): ISO 2.1 und TISAX 2.1 sind verschiedene Zeilen. + const existing = await prisma.policyTemplateVersion.findUnique({ + where: { framework_version: { framework, version: pkg.version } }, + }); + const version = + existing ?? + (await prisma.policyTemplateVersion.create({ + data: { + framework, + version: pkg.version, + status: publish ? "PUBLISHED" : "DRAFT", + publishedBy: publish ? (options.publishedBy ?? null) : null, + publishedAt: publish ? new Date() : null, + }, + })); + if (existing && publish && existing.status !== "PUBLISHED") { + await prisma.policyTemplateVersion.update({ + where: { id: existing.id }, + data: { status: "PUBLISHED", publishedAt: new Date(), publishedBy: options.publishedBy ?? null }, + }); + } + + const versionId = version.id; + // Inhalte dieser Sprache vollständig ersetzen (idempotenter Sync). + await prisma.$transaction([ + prisma.policyTemplateDoc.deleteMany({ where: { versionId, locale } }), + prisma.policyTemplateRequirement.deleteMany({ where: { versionId, locale } }), + prisma.policyTemplateVariable.deleteMany({ where: { versionId, locale } }), + prisma.policyTemplateBaselineParam.deleteMany({ where: { versionId, locale } }), + prisma.policyTemplateEvidence.deleteMany({ where: { versionId, locale } }), + prisma.policyTemplateDoc.createMany({ + data: pkg.documents.map((d) => ({ + versionId, locale, code: d.code, type: d.type, title: d.title, + policyCode: d.policyCode, fulfills: d.fulfills, rawMarkdown: d.rawMarkdown, orderIdx: d.orderIdx, + })), + }), + prisma.policyTemplateRequirement.createMany({ + data: pkg.requirements.map((r) => ({ + versionId, locale, reqId: r.reqId, policyCode: r.policyCode, control: r.control, + obligation: r.obligation, condition: r.condition, requirement: r.requirement, + implementation: r.implementation, vaCodes: r.vaCodes, nachweisLink: r.nachweisLink, + })), + }), + prisma.policyTemplateVariable.createMany({ + data: pkg.variables.map((v) => ({ + versionId, locale, key: v.key, title: v.title, kind: v.kind, + groupName: v.groupName, value: v.value, required: v.required, orderIdx: v.orderIdx, + })), + }), + prisma.policyTemplateBaselineParam.createMany({ + data: pkg.baseline.map((b) => ({ + versionId, locale, blId: b.blId, section: b.section, name: b.name, vorgabe: b.vorgabe, orderIdx: b.orderIdx, + })), + }), + prisma.policyTemplateEvidence.createMany({ + data: pkg.evidence.map((e) => ({ + versionId, locale, nr: e.nr, policyCode: e.policyCode, nachweis: e.nachweis, + quelle: e.quelle, verantwortlich: e.verantwortlich, turnus: e.turnus, + })), + }), + ]); + + return { versionId, version: version.version }; +} + +/** + * Aktuell veröffentlichte Vorlagen-Version in der gewünschten Sprache als `ParsedPackage`. + * Liefert null, wenn keine veröffentlichte Version existiert oder die Sprache keine + * Dokumente enthält (→ Aufrufer nutzt den Datei-Fallback). + */ +export async function loadPublishedPackage( + prisma: PrismaClient, + locale: string, + framework: Framework = "TISAX", +): Promise<ParsedPackage | null> { + const version = await prisma.policyTemplateVersion.findFirst({ + where: { status: "PUBLISHED", framework }, + orderBy: [{ publishedAt: "desc" }, { createdAt: "desc" }], + }); + if (!version) return null; + + const [docs, reqs, vars, baseline, evidence] = await Promise.all([ + prisma.policyTemplateDoc.findMany({ where: { versionId: version.id, locale }, orderBy: { orderIdx: "asc" } }), + prisma.policyTemplateRequirement.findMany({ where: { versionId: version.id, locale }, orderBy: { orderIdx: "asc" } }), + prisma.policyTemplateVariable.findMany({ where: { versionId: version.id, locale }, orderBy: { orderIdx: "asc" } }), + prisma.policyTemplateBaselineParam.findMany({ where: { versionId: version.id, locale }, orderBy: { orderIdx: "asc" } }), + prisma.policyTemplateEvidence.findMany({ where: { versionId: version.id, locale }, orderBy: { nr: "asc" } }), + ]); + if (docs.length === 0) return null; // Sprache (noch) nicht befüllt → Fallback + + return { + version: version.version, + documents: docs.map((d) => ({ + code: d.code, type: d.type as DocType, title: d.title, policyCode: d.policyCode, + fulfills: d.fulfills, rawMarkdown: d.rawMarkdown, orderIdx: d.orderIdx, + })), + requirements: reqs.map((r) => ({ + reqId: r.reqId, policyCode: r.policyCode, control: r.control, obligation: r.obligation, + condition: r.condition, requirement: r.requirement, implementation: r.implementation, + vaCodes: r.vaCodes, nachweisLink: r.nachweisLink, + })), + variables: vars.map((v) => ({ + key: v.key, title: v.title, kind: v.kind, groupName: v.groupName, + value: v.value, required: v.required, orderIdx: v.orderIdx, + })), + baseline: baseline.map((b) => ({ + blId: b.blId, section: b.section, name: b.name, vorgabe: b.vorgabe, orderIdx: b.orderIdx, + })), + evidence: evidence.map((e) => ({ + nr: e.nr, policyCode: e.policyCode, nachweis: e.nachweis, quelle: e.quelle, + verantwortlich: e.verantwortlich, turnus: e.turnus, + })), + }; +} + +/** Sprachpräferenz eines Mandanten (Default "de"). Owner-Client (RLS-Bypass) — für Plattform- UND Mandanten-Aufrufer nutzbar. */ +export async function getTenantLocale(prisma: PrismaClient, tenantId: string): Promise<string> { + const s = await prisma.tenantSettings.findUnique({ where: { tenantId }, select: { locale: true } }); + return s?.locale ?? "de"; +} + +/** + * Auflösen des Vorlagenpakets für einen Mandanten: veröffentlichte DB-Version in der + * Sprache des Mandanten → DE-Fallback → Datei-Fallback. So funktioniert der Import + * identisch, egal ob die DB-Ablage schon befüllt ist. + */ +export async function resolvePackageForTenant( + prisma: PrismaClient, + tenantId: string, + seedDir: string, + framework: Framework = "TISAX", +): Promise<{ pkg: ParsedPackage; source: "db" | "file"; locale: string }> { + const locale = await getTenantLocale(prisma, tenantId); + const inLocale = await loadPublishedPackage(prisma, locale, framework); + if (inLocale) return { pkg: inLocale, source: "db", locale }; + if (locale !== "de") { + const de = await loadPublishedPackage(prisma, "de", framework); + if (de) return { pkg: de, source: "db", locale: "de" }; + } + // Datei-Fallback: das framework-passende Mapping (mapping.json / mapping-iso.json). + return { pkg: parsePackageFiles(seedDir, mappingFileFor(framework)), source: "file", locale }; +} + +/** Verfügbare Paketversion für den Update-Vergleich: veröffentlichte DB-Version, sonst Datei-Version. */ +export async function getAvailableVersion( + prisma: PrismaClient, + seedDir: string, + framework: Framework = "TISAX", +): Promise<string> { + const v = await prisma.policyTemplateVersion.findFirst({ + where: { status: "PUBLISHED", framework }, + orderBy: [{ publishedAt: "desc" }, { createdAt: "desc" }], + select: { version: true }, + }); + return v?.version ?? readPackageVersion(seedDir, mappingFileFor(framework)); +} + +/** + * Frameworks eines Mandanten (AP1), Primär-Framework zuerst. Fällt auf `["TISAX"]` + * zurück, falls (noch) keine `TenantFramework`-Zeile existiert — so bleibt jeder + * Bestands-/Alt-Mandant ohne Zeile als TISAX lauffähig (Fail-safe zu Invariante 3). + * Owner-Client (RLS-Bypass) — für Plattform- UND Mandanten-Aufrufer nutzbar. + */ +export async function getTenantFrameworks(prisma: PrismaClient, tenantId: string): Promise<Framework[]> { + const rows = await prisma.tenantFramework.findMany({ + where: { tenantId }, + orderBy: [{ isPrimary: "desc" }, { createdAt: "asc" }], + select: { framework: true }, + }); + return rows.length ? rows.map((r) => r.framework) : ["TISAX"]; +} + +/** Primär-Framework eines Mandanten (erstes aus {@link getTenantFrameworks}). */ +export async function getTenantPrimaryFramework(prisma: PrismaClient, tenantId: string): Promise<Framework> { + return (await getTenantFrameworks(prisma, tenantId))[0]; +} diff --git a/public/assets/logo/certvia-favicon.svg b/public/assets/logo/certvia-favicon.svg new file mode 100644 index 0000000..69cff9d --- /dev/null +++ b/public/assets/logo/certvia-favicon.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="Certvia"> + <rect x="0" y="0" width="64" height="64" rx="14" fill="#5d52a3"/> + <path d="M46 20 A17 17 0 1 0 46 44" fill="none" stroke="#ffffff" stroke-width="6" stroke-linecap="round"/> + <path d="M27 32 l6 6 l12 -15" fill="none" stroke="#f2a7ef" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/> +</svg> diff --git a/public/assets/logo/certvia-lockup-positiv-1024.png b/public/assets/logo/certvia-lockup-positiv-1024.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e613fe002c2ce123e4b87c39848f334013d9eb GIT binary patch literal 22486 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 DML*MO literal 0 HcmV?d00001 diff --git a/public/assets/logo/certvia-lockup-positiv.svg b/public/assets/logo/certvia-lockup-positiv.svg new file mode 100644 index 0000000..6348447 --- /dev/null +++ b/public/assets/logo/certvia-lockup-positiv.svg @@ -0,0 +1,34 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 380 96" width="380" height="96" role="img" aria-label="Certvia"> + <title>Certvia + + + + + + + + + + Certvia + + diff --git a/public/assets/logo/certvia-mark-anthrazit.svg b/public/assets/logo/certvia-mark-anthrazit.svg new file mode 100644 index 0000000..0b644d0 --- /dev/null +++ b/public/assets/logo/certvia-mark-anthrazit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/logo/certvia-mark-grau.svg b/public/assets/logo/certvia-mark-grau.svg new file mode 100644 index 0000000..d172546 --- /dev/null +++ b/public/assets/logo/certvia-mark-grau.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/logo/certvia-mark-negativ-512.png b/public/assets/logo/certvia-mark-negativ-512.png new file mode 100644 index 0000000000000000000000000000000000000000..abd05be91678ef9b59ea052b99aafc44e5b9c834 GIT binary patch literal 11220 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 JN_Nx#_&;8o*&qM_ literal 0 HcmV?d00001 diff --git a/public/assets/logo/certvia-mark-negativ.svg b/public/assets/logo/certvia-mark-negativ.svg new file mode 100644 index 0000000..5eaa8a9 --- /dev/null +++ b/public/assets/logo/certvia-mark-negativ.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/logo/certvia-mark-positiv-512.png b/public/assets/logo/certvia-mark-positiv-512.png new file mode 100644 index 0000000000000000000000000000000000000000..7ae2f5c4d6d2d3af8967fc845f79deafd51b80e4 GIT binary patch literal 13989 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 + + + diff --git a/public/assets/logo/gefim-logo.png b/public/assets/logo/gefim-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..92b0e965b722cd14039347aa0cd9bc0e3d2ee925 GIT binary patch literal 40645 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 O0000sFS5y^A}WZiih_IG6PIYBVl)#4mzZTL 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 QvH$=807*qoM6N<$f&~cQyZ`_I literal 0 HcmV?d00001 diff --git a/public/favicon/icon-16.png b/public/favicon/icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..ffadec2f37bb6169e3f565e32ac73814ca6aee7a GIT binary patch literal 572 zcmV-C0>k}@P)7j6Jl}*L`EdoA&4L_9sfmt8XY8r+{~HP+?KYt{=Y6(dn3c|?e{$2 z&+~krp8yDS4IYz1UIkhKBmY(bfd;ZSI2@P|%kanwP&MU*uIyE$ko~KG0gO`UHw=KM zykoW1aN<-8?LH^<_8Jo3mI%F`=INsd=~U*gQP5$a?B)iijZ4=KVqUifbv#OZHpSKk zD+i7=B4S zZLGE6-_gumdXc4kfk9QP>MKbw_2DZ*K%3XW!#5GMnK&CPX6}rsTw%j69BzPGyU&S<%xSd@aIglZQJQ^GhjQ#?sjjfGxxI`xa0000< KMNUMnLSTZlnGMhY literal 0 HcmV?d00001 diff --git a/public/favicon/icon-32.png b/public/favicon/icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..266529ba52eb5166f1d5b0b583351a8053560219 GIT binary patch literal 1178 zcmV;L1ZDe)P)JkboiJW=L?xIX3Wd$))0nX=A$i zA%yq@SUex5vrBp`Ld`#QuF#_c+&BMhI?!X5KPZ%}igRzY30HnuEJEDovG4ppYW4== z(-ffiDVPInjd%X(QV?SQQ!ocWK#>Y0&1I3zW+7w88qzWoSevvA=h6iL1pH&%x$VbY z>!t3OPPD0DBm~=ptDsy)YM!%u9fw`1IARtU&I|a*s5s@O?&rIvF)b;Z3O+KOWD&gm zeij9>>+%lL0TL2HU16)6E$IL`A6_cBSh5tKZ+|;Uxl-lP0Py`i~XRXLWOfn8ORNWQFVMH($I1K6IPptmo7A<4QEE}(E-bm`IX8>sK_EFi| zW@-)wIUs~!i6flNQc8M#_W(GMvV~pi6Y==^D6Ot%G8kg($~a!#ya52;$S9|48<9kI zy%?UrY+wM%amzWDolbm=gCiNK2n6F(8l}~BjBA=nln4N%lnf32t((TK2-mCgO)YqQ zeLBR4dvdT_!%26#t`XnJ=$tlWcmf^m0lmE~Z505M!4Rd@^*Y3ZT&Qeqqq*BRCv#H( zcb!*nzqCIYTa^005Y1hGaj7M;r2DrFYe7%l?S48gtMG?GpEK`SwRF^M$s5s>|ypAI($DxqqiWFd;)u@0he@f;cPx# literal 0 HcmV?d00001 diff --git a/public/favicon/icon-48.png b/public/favicon/icon-48.png new file mode 100644 index 0000000000000000000000000000000000000000..b91ba0ca99e17a6c3a36340d554d962ae97be4f0 GIT binary patch literal 1839 zcmV+~2hjM5P)K zNyb~-%v3)#X=YN#e&~gKicLS%US>K;rWYk~GKpwxG?UgQg9$@060aaa2qM>Vk?XRu z?4Eu50bx1pqI-5pu>Wu8J<3QO)3O*89k%PGD3c4 zwwZ(otH)^GE|0zE|34vwC^CSwY$k)+;-gvpPy+T9R+c2pBW8XC2BU)8t#e?FFIb2wpm zc-=BmQe!!Eu#Be0UR}P@uEG)#%A}dui}~4se2m7x3phA1!q?Zk>FRVa>~IlfF%xIA zU{A9$H_8;y=eE<$Yri?8OGHR3urzT#FYeC^NWQkZlT#;ZsJ`5R5dP0bQKUQhl0mY4 zq2^vhq>=9zW$>rpeHJtq-2zNz13!Hw53^b8Ix^znA8(wa;_8zKTUQi)PF*tq9Veh)!3Gx8try6u8u`U4{o=m}H z((e1yAJkA^+ofw#fStKnEQ#@*AKf06viiGkzd+C>U~OKa=6cvM%Bkb}mK>lUbvd~S z+Pd-X#cJ9IhIGdYTEIeU6t>0M6L)!8BO@aoT@$8R7qT@&yA407Z=|xRMOU101T7#j zX@TF^rK(n4lP!ph;75<-pvb;X_Ig(jC$HA(iZdBOzlCDsqWs31Zuk-|!f0eiZYEYs z6ldxhIDfNEV{0@h>|MWxD6_AK^$t7vd*uaGZ%DNi&>r7WO*Ur5KzZZMiTi<)_Kk|KaJYOiLV>O%4i=IG&*iM*(WJ4H`V;mfzodQptIM?Z z4}?8e&@12^);=jkk%_XHaSXWt__V%}%*AoU&l`Kn<09f?qIooFsmAxy`bMgn+r#A! z=vaa7PXFd(S)wnoouh6Jm3=`=pYN$k667skhAe55_Jc5zb}E7vaN`^QFMHX!@tSMr zsGC23evY<*!GJMlB59{0XaPOl!*sN1iLK91VoronGv;uO^2f84ej;WnX{SP05?6e# zE%kGwOl&R6@Ut5i(b_*ILLg==X{SQTT2WXWtZ_%%AO)N3CFagU+!WlgT9V+&&8h5rY28E~nM?{%(PqA^xOornFa)Tom%3|Rtj|xvFlj3p z3^J=9PGIG#MGOqwrn}QYfQ}MH8MFJzi|cr-AQ@TFreS;QfGz_e)-C2E>*SN+xRZ1EN|jhKmSNKc^F#(Hz9srnT(7q8(WJqNK20k z%3cV#da0ccORK31p(VWo)c~U7&aaSRq55(M)t5V1WV4X-Py+U}SmKw)Fn@joCbNN& z5f6R6PTE@rsIBSb!j~<6wIc-lSK3)r@{uIi9B!o9fCQDYBt+?K6A1(Vl8qksdqDSW zGYJ6#$$MP>+dp3zLWoyqn~h!wC_PfT=ZXxlJgf09z{j)9Ne}wHl6(Lr{m}iw_V*Ty zs;;wu|M~d-f+_@0y?tWW$1tgo{q_B4dsUa52b9kmwR@v~GI^L%iI1M%(bv+uWP=dw z2f}_y&me?=W2z*to=hGB{99!lyPrP%fIxZLdByvL4| d?zs}k@PC%Hk}a}{r|$p&002ovPDHLkV1l?agf{>H literal 0 HcmV?d00001 diff --git a/public/favicon/icon-512.png b/public/favicon/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..bc2828226c841cb427a8ecbd7130cb0bb5710a39 GIT binary patch literal 20500 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¥_D}^8<_{rltw`8!82LNitc(#!s7=*qeehrL^ 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 Aod5s; literal 0 HcmV?d00001 diff --git a/public/favicon/icon-64.png b/public/favicon/icon-64.png new file mode 100644 index 0000000000000000000000000000000000000000..811aa74aa65481190e3cadad81ecddd45fadb3f8 GIT binary patch literal 2450 zcmV;D32pX?P)3bAIRdyDKp)LRzzQ%N(Dq-XjSX0%MU#10sjN zH>7j{4M3?7?6szo9TD7b&PZInZ$TZE((BT8I&D&%B+1A}FYW-cL zE5Mqi8>gtUyal9h1<$__A!rdYPZhqk>LrlG;AV{g1@~^s7LxQ9kQ5RJL&qjZqG#QP z4d3_nHx3Y>Aoq<$0`+~s8dBFngao_oiJtrViy-&?u{v+lB!Rk(|Ixt%2)Mh$75Q9$ z+a&>ngpaMj=rH&dT7-DGAh&R3-@g(-L2lvw0gG)t>< zHwWzjh)-~G-^y9czi|?>JjA(c1oU`)?ECjwc5XjTTWgm|9zxIr$hkG0m22i=cbFSk zwzhP#al>aEDLQ9Lf6BGfbAM$@PnWRS6dwH10`6Wm6N^a|VsYPT?AA0br zDkwW%$FY*Hs3>os{z5D5ZQTIG#M((36Gi&eMCM#Kj?C#vNJA_gv$N7zv1SgNUp*4A z-=?hrKYS#c8?q<*ZTI<9_UVF^{An~<>4>!&)C#x z<}IA4+g4TKV#E4Fh6fL@eAWymCB$j$hYwX7+5y0z0Jq&aO?PqX@%ngW{UJk-eIMDA zC$M1hc#XZOql@AizuE2)6R-dltK#?D|6or!wdb1y?fNp465`04b(O~M6DqHLT7swB zt8>?t5wHN$XNH-ZD=(78DK&Q+74Hr=Rjq(q5k_5umF?N6LjszO3nxDOdt2pnMrzL zyvAPTYGO-Csp0sXwD6Xj;a_;(D^qM=nc(v#VJwD?L zYkvX~K$0LP)}h;0U)M6=f2YmL6Sv+-ytDWE+ool(et!`c+qB{E!5N$LD2Ky4-=dIxL3bfIx|L3>3klD6E^8MT}jWE<0Fx&eTP3FaZhR?e4+nQ#E#* zO~Dp1a8?!9)Z+GZYOd`sg1<i-68%)4cpsrRw(o4@w)YvYzwe!M9`XV^2+I83`RQ_625|l-6FaZlt zRiPh=&CW{GwGSo2V9bp4h9h7BPL^KKwO>7ZEOGHp-L{d45bQ;7FaZm2x~%?kF0Vg| zB6H_G+5=1K3ntYD zzpQK|IVGBL6JmASV`3fTEY2V{*1=cjoAI=dY_6xK#gM-?i~O~785N~pR`+^U-rX7a z&S6?<>@P1D5uf1nTNhLmiCdOra`WvOoH|i|xiogMzLl2dE@T;^qU|K7M3bJG$n5LV zNY5NSWN8dATo*94JZ^VbdGv`Krp?e#mzhn;XEnU^`~gF$aZ``OogH4D{q={2zm<{j z{=27n@!5|J*9A;1j{|rw)dWtRsAuKcESyerUyx{N?&P&s4pVY?*q;K72-5}Vzqv$z zxEk6yu&U;ObKgMxhM@SQ-SUnd%iAQ07sKsL7&x_YSN<^>phJ%MExo_F`@ca# zdI~N@f;)CBZx(`|gx96eA>iPqxAS*Fzfibv=ju0*r1jx*D`dD7)wibaH-rPu0*-|C z$0XPt9=}3Dw~)E_^xz0QVEbgHsSWg%CgAytCkK ze;17Ch?bvQn5IZ#xe(j}TmvKm+821jOB;yuAk_-^*rLksY}}Q9Y`B~L3m2tgvG=L3 Q)&Kwi07*qoM6N<$f}i-sxBvhE literal 0 HcmV?d00001 diff --git a/public/favicon/maskable-512.png b/public/favicon/maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..f2e8ebd8d949db0528000233b722577031bc2ba9 GIT binary patch literal 11933 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 literal 0 HcmV?d00001 diff --git a/public/favicon/pwa-192.png b/public/favicon/pwa-192.png new file mode 100644 index 0000000000000000000000000000000000000000..25438d5bcc8a57ff3eed4bc41ed03efdd167155b GIT binary patch literal 7188 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 literal 0 HcmV?d00001 diff --git a/public/favicon/pwa-512.png b/public/favicon/pwa-512.png new file mode 100644 index 0000000000000000000000000000000000000000..bc2828226c841cb427a8ecbd7130cb0bb5710a39 GIT binary patch literal 20500 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¥_D}^8<_{rltw`8!82LNitc(#!s7=*qeehrL^ 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 Aod5s; literal 0 HcmV?d00001 diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 0000000..d18c52e --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,13 @@ +{ + "name": "Certvia", + "short_name": "Certvia", + "description": "Informationssicherheit. Endlich einfach.", + "theme_color": "#5d52a3", + "background_color": "#0e1220", + "display": "standalone", + "icons": [ + { "src": "/favicon/pwa-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/favicon/pwa-512.png", "sizes": "512x512", "type": "image/png" }, + { "src": "/favicon/maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } + ] +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..e508720 --- /dev/null +++ b/renovate.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":dependencyDashboard", + ":semanticCommits", + ":prConcurrentLimit10" + ], + "timezone": "Europe/Berlin", + "schedule": ["before 6am on monday"], + "labels": ["dependencies"], + "commitMessagePrefix": "chore(deps):", + "rangeStrategy": "bump", + "postUpdateOptions": ["npmDedupe"], + "vulnerabilityAlerts": { + "labels": ["security"], + "schedule": ["at any time"] + }, + "osvVulnerabilityAlerts": true, + "lockFileMaintenance": { + "enabled": true, + "schedule": ["before 6am on the first day of the month"] + }, + "packageRules": [ + { + "description": "Sicherheitsupdates sofort und priorisiert (nicht auf das Wochenfenster warten).", + "matchDatasources": ["npm"], + "isVulnerabilityAlert": true, + "prPriority": 20, + "schedule": ["at any time"] + }, + { + "description": "Nicht-Major-Updates gebündelt (weniger PR-Rauschen).", + "matchUpdateTypes": ["minor", "patch"], + "groupName": "npm non-major" + }, + { + "description": "AUTH KRITISCH: next-auth/@auth/core ist eine Beta (5.x). Updates NICHT automatisch, sondern einzeln, mit manuellem Review — Auth-Regressionen (siehe F-01) können 'fail open' bedeuten. Auto-Merge hier bewusst AUS.", + "matchPackageNames": ["next-auth", "@auth/core"], + "groupName": "auth (manuelles Review!)", + "labels": ["dependencies", "auth-review-erforderlich"], + "automerge": false, + "minimumReleaseAge": "7 days", + "prPriority": 5 + }, + { + "description": "Next.js separat halten (Framework-Major-Sprünge brauchen Regressionstest).", + "matchPackageNames": ["next", "@next/env", "eslint-config-next"], + "groupName": "next.js", + "automerge": false + }, + { + "description": "Prisma zusammen aktualisieren (Client, Engine und CLI müssen versionsgleich sein).", + "matchPackageNames": ["prisma", "@prisma/client", "@prisma/adapter-pg"], + "groupName": "prisma" + }, + { + "description": "Docker-Base-Images und Compose-Images ebenfalls durch Renovate pflegen.", + "matchManagers": ["dockerfile", "docker-compose"], + "groupName": "docker images", + "pinDigests": true + } + ] +} diff --git a/scripts/backfill-risk-5x5.ts b/scripts/backfill-risk-5x5.ts new file mode 100644 index 0000000..d381052 --- /dev/null +++ b/scripts/backfill-risk-5x5.ts @@ -0,0 +1,61 @@ +import "dotenv/config"; +import { prisma } from "../src/server/db"; + +/** + * Backfill 5×5-Risikokriterien für Bestandsmandanten: ergänzt die 5. Eintritts- + * wahrscheinlichkeits-Stufe und die 5. Schadensstufe je Dimension, falls noch nicht + * vorhanden. Die Bewertung (Formular/Matrix/Score) war schon 5×5 — nur die Kriterien- + * daten waren 4-stufig geseedet. Idempotent (mehrfach ausführbar). + * + * npx tsx scripts/backfill-risk-5x5.ts # alle Mandanten + * TENANT_SLUG=gefim npx tsx scripts/backfill-risk-5x5.ts # nur einer + */ + +// Sinnvolle Default-Texte für Stufe 5 der Standard-Schadensdimensionen (Abgleich per Name). +const LEVEL5: Record = { + "Gesetzes-/Vertragsverstöße": "existenzbedrohende Rechtsfolgen (Lizenzentzug/Haftung)", + "Datenschutz": "besonders schützenswerte Daten in großem Umfang / existenzielle Betroffenheit", + "Persönliche Unversehrtheit": "Lebensgefahr für viele / Todesfolge", + "Aufgabenerfüllung": "vollständiger, dauerhafter Ausfall der Organisation", + "Innen-/Außenwirkung (Reputation)": "existenzbedrohender, dauerhafter Reputationsverlust", + "Störungs-/Ausfallzeit": "> 1 Monat / dauerhaft", + "Finanzielle Auswirkungen": "existenzbedrohend (> 1 Mio €)", +}; +const FALLBACK5 = "(bitte definieren)"; + +async function main() { + const slug = process.env.TENANT_SLUG?.trim().toLowerCase(); + const tenants = await prisma.tenant.findMany({ where: slug ? { slug } : {}, select: { id: true, slug: true } }); + if (!tenants.length) { console.log("Keine Mandanten gefunden."); return; } + + for (const t of tenants) { + let ew5 = 0, dim5 = 0; + + // EW-Stufe 5 ergänzen, falls nicht vorhanden + const hasEw5 = await prisma.riskEwLevel.findFirst({ where: { tenantId: t.id, level: 5 } }); + if (!hasEw5) { + // Nur ergänzen, wenn überhaupt EW-Stufen existieren (sonst provisioniert der Mandant sie neu). + const anyEw = await prisma.riskEwLevel.count({ where: { tenantId: t.id } }); + if (anyEw > 0) { + await prisma.riskEwLevel.create({ data: { tenantId: t.id, level: 5, label: "Nahezu sicher", definition: "Ereignis ist praktisch dauerhaft gegeben oder tritt ständig ein." } }); + ew5 = 1; + } + } + + // Schadensdimensionen: je Dimension "5" ergänzen, falls fehlt + const dims = await prisma.riskDamageDimension.findMany({ where: { tenantId: t.id } }); + for (const d of dims) { + const levels = (d.levels ?? {}) as Record; + if (levels["5"] == null || levels["5"] === "") { + levels["5"] = LEVEL5[d.name] ?? FALLBACK5; + await prisma.riskDamageDimension.update({ where: { id: d.id }, data: { levels } }); + dim5++; + } + } + + console.log(`Mandant ${t.slug}: EW-Stufe 5 ${ew5 ? "ergänzt" : "bereits vorhanden/übersprungen"}, ${dim5} Schadensdimension(en) um Stufe 5 ergänzt.`); + } + console.log("Fertig."); +} + +main().then(() => process.exit(0)).catch((e) => { console.error(e); process.exit(1); }); diff --git a/scripts/backup-worker.ts b/scripts/backup-worker.ts new file mode 100644 index 0000000..f05d891 --- /dev/null +++ b/scripts/backup-worker.ts @@ -0,0 +1,41 @@ +import "dotenv/config"; +import { isBackupQueueEnabled } from "../src/server/backup/queue"; +import { startBackupWorker, shutdownBackupWorker } from "../src/server/backup/worker"; + +/** + * Einstiegspunkt des Backup-/DSGVO-Ops-Workers (`npm run worker:backup`). + * + * Eigener Prozess/Container neben der App (analog Mail-Worker), damit der + * destruktive Portal-Restore, „Export jetzt" und die DSGVO-Zustellung unabhängig + * vom Web-Request-Lebenszyklus laufen (Timeouts/Progress/Audit). Ohne `REDIS_URL` + * gibt es keinen Worker-Betrieb — die Enqueue-Action meldet das und führt NICHTS + * inline aus (Restore ist destruktiv, KONZEPT §4). + */ +async function main() { + if (!isBackupQueueEnabled()) { + console.error( + "[backup-worker] REDIS_URL ist nicht gesetzt. Ohne Redis gibt es keinen Backup-Worker; " + + "Portal-Restore/Export/DSGVO können nicht ausgeführt werden.", + ); + process.exit(1); + } + + const worker = startBackupWorker(); + console.info("[backup-worker] bereit — Queue 'backup-ops' (Restore/Export/DSGVO, seriell)."); + + let shuttingDown = false; + const stop = async (signal: string) => { + if (shuttingDown) return; + shuttingDown = true; + console.info(`[backup-worker] ${signal} — fahre herunter…`); + await shutdownBackupWorker(worker); + process.exit(0); + }; + process.on("SIGTERM", () => void stop("SIGTERM")); + process.on("SIGINT", () => void stop("SIGINT")); +} + +main().catch((err) => { + console.error("[backup-worker] Start fehlgeschlagen:", err); + process.exit(1); +}); diff --git a/scripts/bootstrap-admin.ts b/scripts/bootstrap-admin.ts new file mode 100644 index 0000000..850afca --- /dev/null +++ b/scripts/bootstrap-admin.ts @@ -0,0 +1,83 @@ +import "dotenv/config"; +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { hashPassword } from "@/server/password"; +import { provisionTenant } from "@/server/provision"; + +/** + * Erst-Bootstrap für Produktiv (Ersatz für den Demo-Seed, der nur für Test/Dev ist). + * Ohne diesen Schritt gibt es in Prod keinen Zugang. + * + * Legt an: + * 1. Ersten Mandanten + Mandanten-Admin → Login unter /login + * 2. Plattform-Admin (Superadmin, eigener Store) → Login unter /platform/login (MFA + * wird beim ersten Login eingerichtet) + * Beide mit denselben Zugangsdaten (BOOTSTRAP_ADMIN_*), analog zum Seed. + * + * Ausführung: im migrate-Job nach `prisma migrate deploy`, gesteuert per + * BOOTSTRAP_ADMIN=true (siehe docker-compose.coolify.yml, docs/DEPLOY-PROD-CONTABO.md). + * + * Idempotent: provisionTenant und der platformAdmin.upsert nutzen upserts; ein bereits + * gesetztes Passwort wird beim erneuten Lauf NICHT überschrieben. + * + * Erforderliche Umgebungsvariablen: + * BOOTSTRAP_ADMIN_EMAIL, BOOTSTRAP_ADMIN_PASSWORD, BOOTSTRAP_ADMIN_NAME + * BOOTSTRAP_TENANT_NAME, BOOTSTRAP_TENANT_SLUG + * Optional: + * BOOTSTRAP_TENANT_SHORT, BOOTSTRAP_TENANT_SECTOR + */ + +const prisma = new PrismaClient({ + adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), +}); + +function req(name: string): string { + const v = process.env[name]; + if (!v || v.trim() === "") { + console.error(`✖ Bootstrap abgebrochen: Umgebungsvariable ${name} fehlt.`); + process.exit(1); + } + return v.trim(); +} + +async function main() { + const email = req("BOOTSTRAP_ADMIN_EMAIL").toLowerCase(); + const password = req("BOOTSTRAP_ADMIN_PASSWORD"); + const name = req("BOOTSTRAP_ADMIN_NAME"); + const tenantName = req("BOOTSTRAP_TENANT_NAME"); + const tenantSlug = req("BOOTSTRAP_TENANT_SLUG").toLowerCase(); + const short = process.env.BOOTSTRAP_TENANT_SHORT?.trim() || undefined; + const sector = process.env.BOOTSTRAP_TENANT_SECTOR?.trim() || undefined; + + // 1. Mandant + Mandanten-Admin (Zugang /login). Idempotent (upserts). + const tenant = await provisionTenant(prisma, { + name: tenantName, + slug: tenantSlug, + short, + sector, + admin: { email, name, password }, + }); + + // 2. Plattform-Admin / Superadmin (Zugang /platform/login, MFA beim ersten Login). + // upsert: Passwort nur bei Neuanlage setzen — bei erneutem Lauf nicht zurücksetzen. + await prisma.platformAdmin.upsert({ + where: { email }, + update: { name, status: "ACTIVE" }, + create: { email, name, passwordHash: await hashPassword(password), status: "ACTIVE" }, + }); + + console.log( + `✔ Bootstrap fertig: Mandant "${tenant.name}" (${tenantSlug}), Mandanten-Admin + Plattform-Admin ${email} angelegt.` + ); + console.log( + " → /platform/login = Superadmin (MFA beim ersten Login), /login = Mandanten-Zugang. Passwort nach erstem Login ändern." + ); +} + +main() + .then(() => prisma.$disconnect()) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/build-and-push-images.sh b/scripts/build-and-push-images.sh new file mode 100755 index 0000000..19b74e6 --- /dev/null +++ b/scripts/build-and-push-images.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Plan B — Prod-Images auf einem leistungsfähigen amd64-Host bauen und in die +# Registry pushen, damit der Prod-Host (Coolify) nur noch PULLT statt zu bauen. +# +# Voraussetzungen auf dem Build-Host: +# - Docker mit BuildKit, Architektur amd64 (empfohlen: interner Server, der die +# Test-Instanz baut). Auf arm64 (z. B. Mac) läuft es via Emulation, aber langsam. +# - Vorher an der Registry angemeldet: docker login "$REGISTRY_HOST" +# +# Aufruf (im Repo-Root, auf dem gewünschten Commit ausgecheckt): +# REGISTRY=git.certvia.de/msolarczek TAG=$(git rev-parse --short HEAD) ./scripts/build-and-push-images.sh +# +# Env-Variablen: +# REGISTRY Image-Präfix (Default: git.certvia.de/msolarczek) +# TAG Image-Tag (Default: kurzer Git-SHA des aktuellen HEAD) +# PLATFORM Zielplattform (Default: linux/amd64 — passend zum Prod-Host) +# ALSO_MAIN wenn "true": zusätzlich das bewegliche Tag :main setzen/pushen +set -euo pipefail + +REGISTRY="${REGISTRY:-git.certvia.de/msolarczek}" +TAG="${TAG:-$(git rev-parse --short HEAD)}" +PLATFORM="${PLATFORM:-linux/amd64}" +ALSO_MAIN="${ALSO_MAIN:-false}" +REGISTRY_HOST="${REGISTRY%%/*}" + +echo ">> Registry: $REGISTRY" +echo ">> Tag: $TAG" +echo ">> Plattform: $PLATFORM" +echo ">> Login-Host: $REGISTRY_HOST (vorher: docker login $REGISTRY_HOST)" +echo + +export DOCKER_BUILDKIT=1 + +# target -> Image-Name (siehe docker-compose.coolify.prebuilt.yml) +build_one() { + local target="$1" name="$2" + echo ">> Baue $name (target=$target) ..." + docker build --platform "$PLATFORM" --target "$target" \ + -t "$REGISTRY/$name:$TAG" \ + $( [ "$ALSO_MAIN" = "true" ] && echo -t "$REGISTRY/$name:main" ) \ + . +} + +# migrate + runner teilen sich die teuren Stages deps/builder (npm ci + next build). +# Sequentiell auf demselben Host -> zweiter Build nutzt den Layer-Cache des ersten. +build_one runner certvia-app +build_one migrate certvia-migrate +build_one garage certvia-garage + +echo +echo ">> Push ..." +for name in certvia-app certvia-migrate certvia-garage; do + docker push "$REGISTRY/$name:$TAG" + [ "$ALSO_MAIN" = "true" ] && docker push "$REGISTRY/$name:main" || true +done + +echo +echo ">> Fertig. In Coolify (Prod) setzen: IMAGE_TAG=$TAG (und ggf. REGISTRY=$REGISTRY)" diff --git a/scripts/build-c1-scope.ts b/scripts/build-c1-scope.ts new file mode 100644 index 0000000..028fe2a --- /dev/null +++ b/scripts/build-c1-scope.ts @@ -0,0 +1,63 @@ +// Generator (Story A2-2): parst die C1-Scoping-Tabelle (Fachcontent) in die +// maschinenlesbare Scope-Datengrundlage `seed/scoping/c1-scope.json`. +// Lauf: npx tsx scripts/build-c1-scope.ts +// +// Spalten der C1-Tabelle: Control | Anforderungs-ID | Typ | AL2 | AL3 | Prüfziel | Scope-Bedingung(Flag) +// `condition` wird normalisiert: exaktes Feature-Flag (FLAG_*) → Flag-Name, sonst null +// ("immer im Scope" bzw. "Prüfziel … aktiv" werden allein über das Prüfziel gegatet). + +import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; +import { dirname, resolve } from "node:path"; + +const SRC = resolve("docs/wizard-uebergabe/02_Fachcontent_C1-C9/C1_Scoping-AL-Pruefziel.md"); +const OUT = resolve("seed/scoping/c1-scope.json"); + +const PRUEFZIEL: Record = { + Informationssicherheit: "informationssicherheit", + Prototypenschutz: "prototypenschutz", + Datenschutz: "datenschutz", +}; + +const FLAG_RE = /^FLAG_[A-Z_]+$/; + +interface C1Row { + id: string; + control: string; + type: "MUSS" | "SOLL" | "HOCH" | "SEHR HOCH"; + al2: boolean; + al3: boolean; + pruefziel: string; + condition: string | null; +} + +const rows: C1Row[] = []; +for (const line of readFileSync(SRC, "utf8").split("\n")) { + if (!line.startsWith("| ")) continue; + const cells = line.split("|").map((c) => c.trim()); + // cells[0] = "" (vor dem ersten |); Nutzdaten ab cells[1] + const [, control, id, type, al2, al3, pruefzielText, condRaw] = cells; + if (!id || id === "Anforderungs-ID" || control.startsWith("---")) continue; // Header/Separator + const pruefziel = PRUEFZIEL[pruefzielText]; + if (!pruefziel) continue; // keine gültige Datenzeile + const condClean = (condRaw ?? "").replace(/`/g, "").trim(); + const condition = FLAG_RE.test(condClean) ? condClean : null; + rows.push({ + id, + control, + type: type as C1Row["type"], + al2: al2 === "Ja", + al3: al3 === "Ja", + pruefziel, + condition, + }); +} + +mkdirSync(dirname(OUT), { recursive: true }); +writeFileSync(OUT, JSON.stringify(rows, null, 2) + "\n"); + +// Kurzstatistik zur Kontrolle +const by = (f: (r: C1Row) => string) => rows.reduce>((a, r) => ((a[f(r)] = (a[f(r)] ?? 0) + 1), a), {}); +console.log(`✓ ${rows.length} Anforderungen → seed/scoping/c1-scope.json`); +console.log(" Prüfziele:", JSON.stringify(by((r) => r.pruefziel))); +console.log(" Typen:", JSON.stringify(by((r) => r.type))); +console.log(" Bedingungen:", JSON.stringify(by((r) => r.condition ?? "(immer/Prüfziel)"))); diff --git a/scripts/build-c5-controls.ts b/scripts/build-c5-controls.ts new file mode 100644 index 0000000..c85c1f2 --- /dev/null +++ b/scripts/build-c5-controls.ts @@ -0,0 +1,67 @@ +// Generator (Story A7-2): parst die C5-Control-Belegtabelle (Fachcontent §5, IS-Controls) +// in die maschinenlesbare Reifegrad-Datengrundlage `seed/scoping/c5-controls.json`. +// Lauf: npx tsx scripts/build-c5-controls.ts +// +// Quelle §5-Zeilen: | **Control** Titel | P / V / N (mit (**A**)/(**R**)) | R2-Bed. | R3-Bed. | Ziel | +// - policy (P): L00 | R01..R14 (zuständige Richtlinie[n], „—" = keine) +// - verfahren (V): VA-01..VA-19 (geforderte Verfahren, „—" = in Richtlinie verankert) +// - needsAsset/needsRisk: Belegzelle enthält (**A**) bzw. (**R**) +// - target: Standard-Zielreifegrad der Tabelle (informativ; effektiv wird er zur Laufzeit +// aus dem Scope nach C5 §3 abgeleitet). +// §6 (Proto 8.x / Datenschutz 9.x) ist gruppenbasiert und wird NICHT je Control abgebildet; +// dafür greift zur Laufzeit ein generischer Fallback-Spec. + +import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; +import { dirname, resolve } from "node:path"; + +const SRC = resolve("docs/wizard-uebergabe/02_Fachcontent_C1-C9/C5_Reifegradlogik.md"); +const OUT = resolve("seed/scoping/c5-controls.json"); + +export interface C5ControlSpec { + control: string; + title: string; + policy: string[]; + verfahren: string[]; + needsAsset: boolean; + needsRisk: boolean; + target: number; +} + +const CONTROL_RE = /^\|\s*\*\*([0-9]+\.[0-9]+\.[0-9]+(?:-[A-Z]+)?)\*\*\s*([^|]*?)\s*\|(.+)$/; + +function codes(cell: string, re: RegExp): string[] { + const out = new Set(); + for (const m of cell.matchAll(re)) out.add(m[0]); + return [...out]; +} + +function parse(md: string): C5ControlSpec[] { + const rows: C5ControlSpec[] = []; + for (const line of md.split("\n")) { + const m = CONTROL_RE.exec(line.trim()); + if (!m) continue; + const [, control, title, rest] = m; + // rest = "Belege | R2 | R3 | Ziel |" + const cells = rest.split("|").map((c) => c.trim()); + const belege = cells[0] ?? ""; + const zielCell = cells[3] ?? cells[cells.length - 2] ?? ""; + const [pPart = "", vPart = ""] = belege.split(" / "); + const target = Number.parseInt(zielCell.replace(/[^0-9]/g, "").charAt(0) || "3", 10); + rows.push({ + control, + title: title.trim(), + policy: codes(pPart, /L00|R[0-9]{2}/g), + verfahren: codes(vPart, /VA-[0-9]{2}/g), + needsAsset: /\*\*A\*\*/.test(belege), + needsRisk: /\*\*R\*\*/.test(belege), + target: Number.isFinite(target) ? target : 3, + }); + } + return rows; +} + +const specs = parse(readFileSync(SRC, "utf8")); +if (specs.length < 40) throw new Error(`C5 §5 unerwartet wenige Controls geparst: ${specs.length}`); +mkdirSync(dirname(OUT), { recursive: true }); +writeFileSync(OUT, JSON.stringify(specs, null, 2) + "\n"); +console.log(`c5-controls.json geschrieben: ${specs.length} Controls`); diff --git a/scripts/check-module-guards.ts b/scripts/check-module-guards.ts new file mode 100644 index 0000000..c5f8c5d --- /dev/null +++ b/scripts/check-module-guards.ts @@ -0,0 +1,145 @@ +/** + * Vollständigkeitscheck der serverseitigen Modul-Durchsetzung (§3.4, Phase-1-Härtung). + * + * Jede mutierende Server-Action eines gegateten Moduls MUSS über einen + * `moduleGuard("")`-Guard laufen (siehe src/server/action-guard.ts), damit ein + * für den Mandanten deaktiviertes Modul auch Writes serverseitig abweist. + * + * Dieses Script erzwingt das statisch: Es kennt die Zuordnung Action-Datei → Modul + * und schlägt fehl (Exit 1 → Build/Test rot), sobald + * - eine neue Action-Datei nicht zugeordnet ist ("vergessener Endpoint"), + * - eine gegatete Datei den erwarteten moduleGuard nicht verwendet, oder + * - eine exportierte Action nicht über `await guard(...)` läuft. + * + * Neue Action-Datei anlegen ⇒ hier eintragen (Modul-Key oder "EXEMPT"). + */ +import { readdirSync, readFileSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { MODULE_KEYS } from "../src/lib/modules"; + +const ACTIONS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "src", "server", "actions"); + +/** Zuordnung Action-Datei → Modul-Key. "EXEMPT" = kein gegatetes Fachmodul (eigene Auth). */ +const ACTION_MODULE: Record = { + "assets.ts": "assets", + // M2 Strukturanalyse: primäre Informations-Assets (Dedup/Autocomplete) → Asset-Modul. + "structure.ts": "assets", + "processes.ts": "bia", + "risks.ts": "risk", + "risk-catalog.ts": "risk", + "measures.ts": "measures", + "tasks.ts": "tasks", + "incidents.ts": "incidents", + // IM-D: mandantenseitige Pflege der E-Mail-Intake-Konfiguration (moduleGuard("incidents") + tenant:manage). + "incident-intake.ts": "incidents", + "suppliers.ts": "suppliers", + "services.ts": "suppliers", + "software.ts": "suppliers", + "projects.ts": "assets", + "onboarding.ts": "onboarding", + "onboarding-facts.ts": "onboarding", + "onboarding-steps.ts": "onboarding", + "onboarding-team.ts": "onboarding", + "soa.ts": "onboarding", + // AP3: ISO-Anwendbarkeitserklärung (eigenes Modul „soa"). + "soa-entries.ts": "soa", + // AP4: Managementklauseln (Kennzahlen/Managementbewertung/CAPA) im Modul „review". + "review.ts": "review", + "gap.ts": "onboarding", + // Audit-Vorbereitung — Modul `audit`. + "audits.ts": "audit", + "audit-evidence.ts": "audit", + "control-descriptions.ts": "audit", + "policies.ts": "policies", + "policy-package.ts": "policies", + // AP5: Dokumentenlenkung (Prüfzyklus, Neuversion/Historie, Lesebestätigung). + "policy-control.ts": "policies", + "policy-upload.ts": "policies", + "hints.ts": "policies", + "register.ts": "policies", + // Plattform-Betrieb (eigene Auth) und Kunden-Einstellungen (tenant:manage) sind + // keine per TenantModule gegateten Fachmodule — eigene Autorisierung, kein moduleGuard. + "admin.ts": "EXEMPT", + // SEC1: Mail-Betriebsfunktionen der Plattform-Administration (Auth über die + // Plattform-Session), kein per TenantModule gegatetes Fachmodul. + "mail.ts": "EXEMPT", + // Backup-Portal: Enqueue-Actions für Portal-Restore/Export/DSGVO-Zustellung. + // Betreiber-/Plattform-Fähigkeit (Auth über requirePlatformFullAdmin + MFA-Step-up), + // kein per TenantModule gegatetes Fachmodul. + "backup-admin.ts": "EXEMPT", + "backup-settings.ts": "EXEMPT", + // IM-D: Betreiber-Provisionierung/Verifizierung der Intake-Konfiguration + Inbound-Review. + // Plattform-Fähigkeit (requirePlatformFullAdmin), kein per TenantModule gegatetes Fachmodul. + "incident-intake-admin.ts": "EXEMPT", + // SEC2: Passwort-Self-Service. Die Reset-Abläufe laufen bewusst OHNE Session + // (der Nutzer ist ausgesperrt); abgesichert über Rate-Limit, Enumeration- + // Neutralität und single-use-Tokens. Die angemeldeten Abläufe nutzen + // requireSession bzw. requirePlatformSession. + "auth-recovery.ts": "EXEMPT", + "platform.ts": "EXEMPT", + "platform-users.ts": "EXEMPT", + "tenant-users.ts": "EXEMPT", + "account.ts": "EXEMPT", + "tenant-switch.ts": "EXEMPT", + "webauthn.ts": "EXEMPT", + "platform-admins.ts": "EXEMPT", + "policy-templates.ts": "EXEMPT", + "tenant-settings.ts": "EXEMPT", +}; + +const errors: string[] = []; +const files = readdirSync(ACTIONS_DIR).filter((f) => f.endsWith(".ts")); + +for (const file of files) { + const mapped = ACTION_MODULE[file]; + if (!mapped) { + errors.push( + `Nicht zugeordnete Action-Datei: ${file} — in scripts/check-module-guards.ts eintragen (Modul-Key oder "EXEMPT").` + ); + continue; + } + + const src = readFileSync(join(ACTIONS_DIR, file), "utf8"); + + if (mapped === "EXEMPT") { + // Auth-Nachweis: entweder ein require*-Guard ODER ein direkter auth()-Aufruf + // (z. B. tenant-switch.ts, das im No-Tenant-Zustand kein requireSession nutzen + // kann, aber die Identity + Mitgliedschaftszugehörigkeit selbst prüft). + if (!/require(Session|Platform\w*|Permission)|\bauth\(\)/.test(src)) { + errors.push(`${file}: als EXEMPT markiert, aber keine erkennbare Auth-Prüfung.`); + } + continue; + } + + if (!MODULE_KEYS.includes(mapped)) { + errors.push(`${file}: unbekannter Modul-Key "${mapped}" (nicht in src/lib/modules.ts).`); + } + if (!src.includes(`moduleGuard("${mapped}")`)) { + errors.push(`${file}: erwartet moduleGuard("${mapped}") — Modul-Gating fehlt oder falscher Key.`); + } + + // Jede exportierte Server-Action muss über await guard(...) laufen. + const exportRe = /export async function (\w+)\s*\(/g; + const positions: { name: string; index: number }[] = []; + let m: RegExpExecArray | null; + while ((m = exportRe.exec(src))) positions.push({ name: m[1], index: m.index }); + for (let i = 0; i < positions.length; i++) { + const start = positions[i].index; + const end = i + 1 < positions.length ? positions[i + 1].index : src.length; + if (!/await guard\(/.test(src.slice(start, end))) { + errors.push( + `${file}: Action "${positions[i].name}" läuft nicht über await guard(...) — Modul-/Rechte-Guard fehlt.` + ); + } + } +} + +if (errors.length) { + console.error("✗ Modul-Guard-Vollständigkeitscheck fehlgeschlagen:"); + for (const e of errors) console.error(" - " + e); + process.exit(1); +} +console.log( + `✓ Modul-Guard-Vollständigkeitscheck: ${files.length} Action-Dateien geprüft — alle mutierenden Actions sind modul- und rechtegegated.` +); diff --git a/scripts/encrypt-mfa-secrets.ts b/scripts/encrypt-mfa-secrets.ts new file mode 100644 index 0000000..ccc9d7c --- /dev/null +++ b/scripts/encrypt-mfa-secrets.ts @@ -0,0 +1,35 @@ +// SEC3-d Backfill: bestehende Klartext-TOTP-Secrets (Identity + PlatformAdmin) verschlüsseln. +// Idempotent — bereits verschlüsselte (enc:v1:) werden übersprungen. Optional: der Code +// akzeptiert Alt-Klartext ohnehin weiter; dieses Skript verschlüsselt ihn aktiv. +// Lauf (mit gesetztem DATABASE_URL + AUTH_SECRET): npx tsx scripts/encrypt-mfa-secrets.ts +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { encryptSecret, isEncrypted } from "../src/server/secret-crypto"; + +const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) }); + +async function main() { + let users = 0; + // Option C: MFA-Secrets leben an der globalen Identity. + for (const u of await prisma.identity.findMany({ where: { mfaSecret: { not: null } }, select: { id: true, mfaSecret: true } })) { + if (u.mfaSecret && !isEncrypted(u.mfaSecret)) { + await prisma.identity.update({ where: { id: u.id }, data: { mfaSecret: encryptSecret(u.mfaSecret) } }); + users++; + } + } + let admins = 0; + for (const a of await prisma.platformAdmin.findMany({ where: { mfaSecret: { not: null } }, select: { id: true, mfaSecret: true } })) { + if (a.mfaSecret && !isEncrypted(a.mfaSecret)) { + await prisma.platformAdmin.update({ where: { id: a.id }, data: { mfaSecret: encryptSecret(a.mfaSecret) } }); + admins++; + } + } + console.log(`Verschlüsselt: ${users} Nutzer-Secret(s), ${admins} Plattform-Admin-Secret(s).`); +} + +main() + .catch((e) => { + console.error("Backfill fehlgeschlagen:", e.message); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/garage-provision.ts b/scripts/garage-provision.ts new file mode 100644 index 0000000..8d1a89f --- /dev/null +++ b/scripts/garage-provision.ts @@ -0,0 +1,265 @@ +import "dotenv/config"; + +/** + * IM/Garage-Migration — idempotentes Provisioning eines Single-Node-Garage + * (docs/KONZEPT-garage-migration.md §6 Lane B, §7 Runbook). + * + * Garage verwaltet Buckets/Keys/Rechte NICHT über die S3-API (`CreateBucket` gibt es + * dort nicht), sondern out-of-band. Dieser Init-Job (Compose-Service „garage-provision", + * restart:no, analog „migrate") stellt aus einer leeren Garage reproduzierbar den + * betriebsbereiten Zustand her: + * 1. Layout: dem Node einmalig Zone + Kapazität zuweisen und anwenden (ohne Layout + * lehnt Garage jeden Schreibzugriff mit „no capacity" ab). + * 2. Bucket `S3_BUCKET` (Default isms-documents) anlegen. + * 3. Access-Key deterministisch IMPORTIEREN — aus S3_ACCESS_KEY/S3_SECRET_KEY der + * Coolify-Env, damit App-Env und Garage denselben Schlüssel teilen (kein + * Nachpflegen erzeugter Keys). + * 4. Key→Bucket-Rechte read/write setzen. + * 5. Optional denselben Ablauf für einen separaten Backup-Bucket (BACKUP_S3_BUCKET), + * falls der Backup-Store auf S3 statt BACKUP_LOCAL_DIR läuft. + * + * WARUM Admin-API (HTTP) statt `garage`-CLI: Der Job läuft im schlanken „migrate"-Image + * (Node/tsx) — kein Garage-Binary, kein geteiltes meta-Volume, kein Node-Key nötig. Die + * Admin-API v1 ist gegen die gepinnte Garage-Version (v1.2.0) stabil und liefert klare + * Statuscodes (409 = „existiert bereits" → als Erfolg gewertet). Alle Schritte sind + * idempotent: bei JEDEM Deploy lauffähig, „already exists" ist kein Fehler. + * + * Fail-/No-op-Verhalten (Deployment-Falle: ein Init-Container darf den Stack nicht + * reißen): Ist `GARAGE_ADMIN_TOKEN` NICHT gesetzt, gilt Garage als nicht in Betrieb + * (z. B. lokaler/Stub-Betrieb) → sauberer No-op (Exit 0). Ist der Token gesetzt, aber + * Pflicht-Config (S3-Key) fehlt oder die Garage ist nicht erreichbar → klare Meldung + + * Exit ≠ 0. Es werden KEINE Secrets geloggt (Access-Key-ID ist der öffentliche Teil). + */ + +interface Cfg { + adminUrl: string; + adminToken: string; + accessKeyId: string; + secretKey: string; + bucket: string; + backupBucket: string | null; + zone: string; + capacityBytes: number; +} + +function log(msg: string): void { + // stdout mit Zeitstempel; Coolify erfasst die Logs. Bei „Container weg ohne Logs" + // zusätzlich in eine Datei spiegeln (GARAGE_PROVISION_LOG), siehe DEPLOY-COOLIFY. + const line = `[garage-provision] ${msg}`; + console.log(line); +} + +function readCfg(): Cfg | null { + const adminToken = process.env.GARAGE_ADMIN_TOKEN?.trim(); + if (!adminToken) { + // Garage nicht in Betrieb → No-op (siehe Datei-Doc, Deployment-Falle). + log("GARAGE_ADMIN_TOKEN nicht gesetzt — Garage-Provisioning übersprungen (No-op)."); + return null; + } + const accessKeyId = process.env.S3_ACCESS_KEY?.trim(); + const secretKey = process.env.S3_SECRET_KEY?.trim(); + const bucket = process.env.S3_BUCKET?.trim() || "isms-documents"; + if (!accessKeyId || !secretKey) { + throw new Error( + "GARAGE_ADMIN_TOKEN ist gesetzt, aber S3_ACCESS_KEY/S3_SECRET_KEY fehlen. " + + "Beide müssen den zu importierenden Garage-Key definieren (App-Env == Garage).", + ); + } + // Garage erzwingt beim Key-Import ein festes Format (sonst HTTP 400). Früh & klar + // prüfen statt kryptisch beim Import scheitern: + // Access-Key-ID = "GK" + 24 Hex · Secret = 64 Hex. + // S3_ACCESS_KEY: echo "GK$(openssl rand -hex 12)" + // S3_SECRET_KEY: openssl rand -hex 32 + if (!/^GK[0-9a-f]{24}$/.test(accessKeyId)) { + throw new Error( + `S3_ACCESS_KEY hat nicht das von Garage geforderte Format „GK" + 24 Hex-Zeichen ` + + `(erhalten: „${accessKeyId}"). Erzeugen: echo "GK$(openssl rand -hex 12)".`, + ); + } + if (!/^[0-9a-f]{64}$/i.test(secretKey)) { + throw new Error("S3_SECRET_KEY muss 64 Hex-Zeichen sein (openssl rand -hex 32)."); + } + const capacityBytes = Number(process.env.GARAGE_CAPACITY_BYTES ?? "100000000000"); // 100 GB nominal + if (!Number.isFinite(capacityBytes) || capacityBytes <= 0) { + throw new Error(`GARAGE_CAPACITY_BYTES ungültig: ${process.env.GARAGE_CAPACITY_BYTES}`); + } + return { + adminUrl: (process.env.GARAGE_ADMIN_URL?.trim() || "http://garage:3903").replace(/\/+$/, ""), + adminToken, + accessKeyId, + secretKey, + bucket, + backupBucket: process.env.BACKUP_S3_BUCKET?.trim() || null, + zone: process.env.GARAGE_ZONE?.trim() || "dc1", + capacityBytes, + }; +} + +/** Admin-API-Aufruf. `expectMissing` erlaubt 404 (Existenzprüfung) ohne Wurf. */ +async function admin( + cfg: Cfg, + method: string, + path: string, + body?: unknown, +): Promise<{ status: number; json: unknown }> { + const res = await fetch(`${cfg.adminUrl}${path}`, { + method, + headers: { + Authorization: `Bearer ${cfg.adminToken}`, + ...(body !== undefined ? { "Content-Type": "application/json" } : {}), + }, + body: body !== undefined ? JSON.stringify(body) : undefined, + }); + let json: unknown = null; + const text = await res.text(); + if (text) { + try { + json = JSON.parse(text); + } catch { + json = text; + } + } + return { status: res.status, json }; +} + +/** Wartet, bis die Admin-API /health mit 200 antwortet (Garage-Start abwarten). */ +async function waitForHealth(cfg: Cfg, timeoutMs = 90_000): Promise { + const deadline = Date.now() + timeoutMs; + let lastErr = ""; + while (Date.now() < deadline) { + try { + const res = await fetch(`${cfg.adminUrl}/health`); + if (res.status === 200) { + log("Garage Admin-API erreichbar (/health 200)."); + return; + } + lastErr = `HTTP ${res.status}`; + } catch (err) { + lastErr = err instanceof Error ? err.message : String(err); + } + await new Promise((r) => setTimeout(r, 2000)); + } + throw new Error(`Garage Admin-API nicht erreichbar (${cfg.adminUrl}/health): ${lastErr}`); +} + +/** Layout einmalig sicherstellen: Node bekommt Zone + Kapazität (nur falls noch ohne Rolle). */ +async function ensureLayout(cfg: Cfg): Promise { + const status = await admin(cfg, "GET", "/v1/status"); + if (status.status !== 200) throw new Error(`GET /v1/status fehlgeschlagen (HTTP ${status.status}).`); + const nodeId = (status.json as { node?: string })?.node; + if (!nodeId) throw new Error("Konnte die Node-ID nicht aus /v1/status lesen."); + + const layout = await admin(cfg, "GET", "/v1/layout"); + if (layout.status !== 200) throw new Error(`GET /v1/layout fehlgeschlagen (HTTP ${layout.status}).`); + const l = layout.json as { version: number; roles: { id: string }[] }; + if (l.roles.some((r) => r.id === nodeId)) { + log(`Layout bereits gesetzt (Node hat eine Rolle, Version ${l.version}) — übersprungen.`); + return; + } + + log(`Layout wird zugewiesen: Zone „${cfg.zone}", Kapazität ${cfg.capacityBytes} Bytes.`); + const stage = await admin(cfg, "POST", "/v1/layout", [ + { id: nodeId, zone: cfg.zone, capacity: cfg.capacityBytes, tags: [] }, + ]); + if (stage.status !== 200) throw new Error(`Layout-Staging fehlgeschlagen (HTTP ${stage.status}).`); + const apply = await admin(cfg, "POST", "/v1/layout/apply", { version: l.version + 1 }); + if (apply.status !== 200) throw new Error(`Layout-Apply fehlgeschlagen (HTTP ${apply.status}).`); + log(`Layout angewendet (Version ${l.version + 1}).`); +} + +/** Bucket sicherstellen (idempotent). Gibt die Bucket-ID zurück. */ +async function ensureBucket(cfg: Cfg, alias: string): Promise { + const existing = await admin(cfg, "GET", `/v1/bucket?globalAlias=${encodeURIComponent(alias)}`); + if (existing.status === 200) { + log(`Bucket „${alias}" existiert bereits.`); + return (existing.json as { id: string }).id; + } + if (existing.status !== 404) { + throw new Error(`GET /v1/bucket (${alias}) unerwartet (HTTP ${existing.status}).`); + } + const created = await admin(cfg, "POST", "/v1/bucket", { globalAlias: alias }); + if (created.status === 200) { + log(`Bucket „${alias}" angelegt.`); + return (created.json as { id: string }).id; + } + if (created.status === 409) { + // Rennen: parallel angelegt → erneut lesen. + const again = await admin(cfg, "GET", `/v1/bucket?globalAlias=${encodeURIComponent(alias)}`); + if (again.status === 200) { + log(`Bucket „${alias}" existierte bereits (409, Race).`); + return (again.json as { id: string }).id; + } + } + throw new Error(`Bucket „${alias}" konnte nicht angelegt werden (HTTP ${created.status}).`); +} + +/** Access-Key deterministisch importieren (idempotent). */ +async function ensureKey(cfg: Cfg): Promise { + const existing = await admin( + cfg, + "GET", + `/v1/key?id=${encodeURIComponent(cfg.accessKeyId)}&showSecretKey=false`, + ); + if (existing.status === 200) { + log(`Access-Key ${cfg.accessKeyId} existiert bereits — Import übersprungen.`); + return; + } + if (existing.status !== 404) { + throw new Error(`GET /v1/key unerwartet (HTTP ${existing.status}).`); + } + const imported = await admin(cfg, "POST", "/v1/key/import", { + accessKeyId: cfg.accessKeyId, + secretAccessKey: cfg.secretKey, + name: "isms-app", + }); + if (imported.status === 200) { + log(`Access-Key ${cfg.accessKeyId} importiert.`); + return; + } + if (imported.status === 409) { + log(`Access-Key ${cfg.accessKeyId} existierte bereits (409).`); + return; + } + throw new Error( + `Access-Key-Import fehlgeschlagen (HTTP ${imported.status}). ` + + `Hinweis: Ist der Key mit anderem Secret bereits vorhanden, zuerst löschen und neu importieren.`, + ); +} + +/** Key→Bucket-Rechte read/write setzen (idempotent — Garage bestätigt erneut). */ +async function allow(cfg: Cfg, bucketId: string): Promise { + const res = await admin(cfg, "POST", "/v1/bucket/allow", { + bucketId, + accessKeyId: cfg.accessKeyId, + permissions: { read: true, write: true, owner: false }, + }); + if (res.status !== 200) { + throw new Error(`bucket/allow fehlgeschlagen (HTTP ${res.status}).`); + } + log(`Rechte read/write für ${cfg.accessKeyId} auf Bucket ${bucketId} gesetzt.`); +} + +async function main() { + const cfg = readCfg(); + if (!cfg) return; // No-op (kein Admin-Token) + + log(`Ziel: ${cfg.adminUrl} · Bucket „${cfg.bucket}"${cfg.backupBucket ? ` + Backup „${cfg.backupBucket}"` : ""}.`); + await waitForHealth(cfg); + await ensureLayout(cfg); + + const bucketId = await ensureBucket(cfg, cfg.bucket); + await ensureKey(cfg); + await allow(cfg, bucketId); + + if (cfg.backupBucket && cfg.backupBucket !== cfg.bucket) { + const backupId = await ensureBucket(cfg, cfg.backupBucket); + await allow(cfg, backupId); + } + + log("Provisioning abgeschlossen — Garage ist betriebsbereit."); +} + +main().catch((err) => { + console.error(`[garage-provision] FEHLER: ${err instanceof Error ? err.message : String(err)}`); + process.exit(1); +}); diff --git a/scripts/import-c6-hints.ts b/scripts/import-c6-hints.ts new file mode 100644 index 0000000..df98367 --- /dev/null +++ b/scripts/import-c6-hints.ts @@ -0,0 +1,15 @@ +import "dotenv/config"; +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { importImplementationHints } from "../prisma/import-hints"; + +// Standalone-Import der C6-Umsetzungshinweise (Story B5-1). Idempotent. +const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) }); + +async function main() { + const n = await importImplementationHints(prisma); + const total = await prisma.implementationHint.count(); + const proc = await prisma.implementationHint.count({ where: { procurement: true } }); + console.log(JSON.stringify({ parsed: n, inDb: total, procurement: proc })); +} +main().finally(() => prisma.$disconnect()); diff --git a/scripts/import-risk-catalog.ts b/scripts/import-risk-catalog.ts new file mode 100644 index 0000000..3cb91c2 --- /dev/null +++ b/scripts/import-risk-catalog.ts @@ -0,0 +1,15 @@ +import "dotenv/config"; +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { importRiskCatalog } from "../prisma/import-risks"; + +// Standalone-Import des C4-Risikokatalogs (Story A6-1). Idempotent. +const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) }); + +async function main() { + const n = await importRiskCatalog(prisma); + const total = await prisma.riskCatalogEntry.count(); + const cats = await prisma.riskCatalogEntry.groupBy({ by: ["category"], _count: true }); + console.log(JSON.stringify({ parsed: n, inDb: total, categories: cats.length })); +} +main().finally(() => prisma.$disconnect()); diff --git a/scripts/incident-inbound-worker.ts b/scripts/incident-inbound-worker.ts new file mode 100644 index 0000000..6825d76 --- /dev/null +++ b/scripts/incident-inbound-worker.ts @@ -0,0 +1,205 @@ +import "dotenv/config"; +import { parseInbound, type RawHeaders } from "../src/server/incident-inbound/parse"; +import { processInbound } from "../src/server/incident-inbound/process"; + +/** + * IM-D — Einstiegspunkt des Inbound-Mail-Workers (`npm run worker:incident-inbound`). + * + * Eigener Prozess/Container neben der App (analog Mail-/Backup-Worker). Holt Mails + * vom Catch-all-Postfach (`vorfall-@in.certvia.de`, KONZEPT §2/§14.3) per + * IMAP ab, parst sie (rein, parse.ts) und verarbeitet sie (process.ts): Vorfall im + * richtigen Mandanten anlegen ODER in die Betreiber-Review geben. + * + * IMAP-Bibliotheken (imapflow/mailparser) werden BEWUSST dynamisch importiert: + * - der Web-/Build-Pfad zieht sie nie mit ein (reiner Ops-Prozess), + * - `tsc --noEmit` bleibt unabhängig von den Paket-Typdefinitionen grün. + * + * Ohne IMAP-Env (INCIDENT_IMAP_HOST/USER/PASSWORD) gibt es keinen Betrieb — der + * Worker meldet „nicht konfiguriert" und geht in den LEERLAUF (Prozess bleibt am + * Leben), statt sich zu beenden. Grund: mit `restart: unless-stopped` würde ein + * Exit einen Crash-Loop erzeugen, den Coolify als unhealthy wertet und deshalb den + * GESAMTEN Stack (inkl. gesunder App) wieder abreißt. Idle → Container „running", + * Deploy bleibt grün; bei nachträglicher IMAP-Konfig aktiviert ein Neustart den Betrieb. + */ + +interface ImapEnv { + host: string; + port: number; + user: string; + password: string; + tls: boolean; + mailbox: string; + pollMs: number; +} + +function readEnv(): ImapEnv | null { + const host = process.env.INCIDENT_IMAP_HOST?.trim(); + const user = process.env.INCIDENT_IMAP_USER?.trim(); + const password = process.env.INCIDENT_IMAP_PASSWORD; + if (!host || !user || !password) return null; + return { + host, + port: Number(process.env.INCIDENT_IMAP_PORT ?? "993"), + user, + password, + // Default TLS an; nur bei explizit "false"/"0" abschalten (STARTTLS/Plain). + tls: !["false", "0", "no"].includes((process.env.INCIDENT_IMAP_TLS ?? "true").toLowerCase()), + mailbox: process.env.INCIDENT_IMAP_MAILBOX?.trim() || "INBOX", + pollMs: Math.max(15_000, Number(process.env.INCIDENT_IMAP_POLL_MS ?? "60000")), + }; +} + +/** mailparser-Header (Map) → flache RawHeaders für parse.ts. */ +function toRawHeaders(headerLines: Array<{ key: string; line: string }> | undefined): RawHeaders { + const out: RawHeaders = {}; + for (const h of headerLines ?? []) { + // `line` ist die vollständige "Key: Value"-Zeile; Wert hinter dem ersten ":". + const idx = h.line.indexOf(":"); + const value = idx >= 0 ? h.line.slice(idx + 1).trim() : h.line.trim(); + const key = h.key; + const existing = out[key]; + if (existing === undefined) out[key] = value; + else if (Array.isArray(existing)) existing.push(value); + else out[key] = [existing, value]; + } + return out; +} + +/** + * Hält den Prozess am Leben, bis SIGTERM/SIGINT kommt — statt Crash-Loop bei fehlender + * IMAP-Konfig. Der Heartbeat-Timer hält den Event-Loop offen (Signal-Listener allein + * genügen dafür nicht); bei Signal wird er gestoppt und der Prozess endet sauber (Exit 0). + */ +function idleUntilSignal(): Promise { + return new Promise((resolve) => { + const beat = setInterval(() => {}, 60_000); + const done = (signal: string) => { + clearInterval(beat); + console.info(`[incident-inbound] ${signal} — Leerlauf beendet.`); + resolve(); + }; + process.on("SIGTERM", () => done("SIGTERM")); + process.on("SIGINT", () => done("SIGINT")); + }); +} + +async function main() { + const env = readEnv(); + if (!env) { + console.warn( + "[incident-inbound] IMAP ist nicht konfiguriert (INCIDENT_IMAP_HOST/USER/PASSWORD fehlen). " + + "Ohne Postfach kein E-Mail-to-Ticket-Betrieb — Worker läuft im Leerlauf (kein Crash-Loop). " + + "Setze die INCIDENT_IMAP_*-Variablen und starte den Container neu, um den Betrieb zu aktivieren.", + ); + await idleUntilSignal(); + return; + } + + // Dynamischer Import: hält Web-/Build-Pfad + tsc frei von IMAP-Typen. + let ImapFlow: unknown; + let simpleParser: unknown; + try { + ({ ImapFlow } = (await import("imapflow")) as { ImapFlow: unknown }); + ({ simpleParser } = (await import("mailparser")) as { simpleParser: unknown }); + } catch (err) { + console.error( + "[incident-inbound] Pakete 'imapflow'/'mailparser' nicht installiert. " + + "`npm install imapflow mailparser` im Worker-Image sicherstellen.", + err, + ); + process.exit(1); + } + + /* eslint-disable @typescript-eslint/no-explicit-any */ + const ClientCtor = ImapFlow as any; + const parse = simpleParser as any; + + const client = new ClientCtor({ + host: env.host, + port: env.port, + secure: env.tls, + auth: { user: env.user, pass: env.password }, + logger: false, + }); + + let shuttingDown = false; + const stop = async (signal: string) => { + if (shuttingDown) return; + shuttingDown = true; + console.info(`[incident-inbound] ${signal} — fahre herunter…`); + try { + await client.logout(); + } catch { + /* egal beim Herunterfahren */ + } + process.exit(0); + }; + process.on("SIGTERM", () => void stop("SIGTERM")); + process.on("SIGINT", () => void stop("SIGINT")); + + await client.connect(); + console.info( + `[incident-inbound] verbunden mit ${env.host} (${env.mailbox}) — Intake-Domain ` + + `${process.env.INCIDENT_INTAKE_DOMAIN ?? "in.certvia.de"}, Poll ${env.pollMs}ms.`, + ); + + async function drainOnce(): Promise { + const lock = await client.getMailboxLock(env!.mailbox); + try { + // Nur ungelesene Mails; nach erfolgreicher Verarbeitung als \Seen markieren + // (Idempotenz zusätzlich über Message-ID in process.ts). + for await (const message of client.fetch({ seen: false }, { source: true, uid: true })) { + let handled = false; + try { + const mail = await parse(message.source); + const parsed = parseInbound({ + headers: toRawHeaders(mail.headerLines), + from: mail.from?.text, + subject: mail.subject, + text: mail.text ?? "", + messageId: mail.messageId, + }); + const result = await processInbound(parsed); + const decision = result.decision; + const detail = + decision.action === "incident" + ? `Vorfall ${result.refNo}` + : decision.action === "review" + ? `Review (${decision.review.reason})` + : `ignoriert (${decision.reason})`; + console.info(`[incident-inbound] UID ${message.uid}: ${detail}`); + handled = true; + } catch (err) { + // Verarbeitungsfehler: NICHT als gelesen markieren → nächster Lauf erneut. + console.error(`[incident-inbound] Fehler bei UID ${message.uid}:`, err); + } + if (handled) { + try { + await client.messageFlagsAdd({ uid: message.uid }, ["\\Seen"], { uid: true }); + } catch (err) { + console.error(`[incident-inbound] Konnte UID ${message.uid} nicht als gelesen markieren:`, err); + } + } + } + } finally { + lock.release(); + } + } + /* eslint-enable @typescript-eslint/no-explicit-any */ + + // Poll-Schleife (robust gegen einzelne Fehlläufe). IMAP-IDLE wäre latenzärmer, das + // Polling ist aber einfacher, ausreichend und übersteht Verbindungsabbrüche. + while (!shuttingDown) { + try { + await drainOnce(); + } catch (err) { + console.error("[incident-inbound] Abholung fehlgeschlagen (nächster Versuch folgt):", err); + } + await new Promise((r) => setTimeout(r, env.pollMs)); + } +} + +main().catch((err) => { + console.error("[incident-inbound] Start fehlgeschlagen:", err); + process.exit(1); +}); diff --git a/scripts/mail-worker.ts b/scripts/mail-worker.ts new file mode 100644 index 0000000..3dc099e --- /dev/null +++ b/scripts/mail-worker.ts @@ -0,0 +1,56 @@ +import "dotenv/config"; +import { getMailConfig } from "../src/server/mail/config"; +import { isQueueEnabled } from "../src/server/mail/queue"; +import { + scheduleDueReminders, + shutdownWorkers, + startMailWorker, + startReminderWorker, +} from "../src/server/mail/worker"; + +/** + * SEC1 — Einstiegspunkt des Mail-Workers (`npm run worker:mail`). + * + * Betriebsmodus: eigener Prozess/Container neben der App (Coolify), damit + * Zustellung, Retry und der tägliche Fristen-Job unabhängig vom Web-Request- + * Lebenszyklus laufen. Ohne `REDIS_URL` gibt es keinen Worker-Betrieb — die App + * versendet dann inline (siehe src/server/mail/queue.ts). + */ +async function main() { + if (!isQueueEnabled()) { + console.error( + "[mail-worker] REDIS_URL ist nicht gesetzt. Ohne Redis läuft der Versand inline in der App; ein Worker wird nicht benötigt.", + ); + process.exit(1); + } + + const { config, reason } = getMailConfig(); + if (!config) { + // Kein harter Abbruch: der Worker läuft weiter und meldet den Zustand — so + // ist nach dem Nachreichen der Secrets kein Neustart-Rennen nötig. + console.warn(`[mail-worker] ${reason}`); + } else { + console.info(`[mail-worker] SMTP ${config.host}:${config.port} (secure=${config.secure})`); + } + + const mailWorker = startMailWorker(); + const reminderWorker = startReminderWorker(); + await scheduleDueReminders(); + console.info("[mail-worker] bereit — Queue 'mail' + Fristen-Job (täglich 07:00 Europe/Berlin)."); + + let shuttingDown = false; + const stop = async (signal: string) => { + if (shuttingDown) return; + shuttingDown = true; + console.info(`[mail-worker] ${signal} — fahre herunter…`); + await shutdownWorkers([mailWorker, reminderWorker]); + process.exit(0); + }; + process.on("SIGTERM", () => void stop("SIGTERM")); + process.on("SIGINT", () => void stop("SIGINT")); +} + +main().catch((err) => { + console.error("[mail-worker] Start fehlgeschlagen:", err); + process.exit(1); +}); diff --git a/scripts/snapshots/framework-assessment-tisax.json b/scripts/snapshots/framework-assessment-tisax.json new file mode 100644 index 0000000..6991e34 --- /dev/null +++ b/scripts/snapshots/framework-assessment-tisax.json @@ -0,0 +1,1233 @@ +{ + "controls": [ + { + "confirmed": null, + "control": "1.1.1", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.1.1 führen", + "actual": 2, + "control": "1.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.2.1", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.2.1 führen", + "actual": 2, + "control": "1.2.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.2.2", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.2.2 führen", + "actual": 2, + "control": "1.2.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.2.3", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.2.3 führen", + "actual": 2, + "control": "1.2.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.3.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.3.1 führen", + "actual": 2, + "control": "1.3.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.3.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.3.2 führen", + "actual": 2, + "control": "1.3.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.3.3", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.3.3 führen", + "actual": 2, + "control": "1.3.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.3.4", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.3.4 führen", + "actual": 2, + "control": "1.3.4", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.4.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.4.1 führen", + "actual": 2, + "control": "1.4.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.5.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.5.1 führen", + "actual": 2, + "control": "1.5.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.5.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.5.2 führen", + "actual": 2, + "control": "1.5.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.6.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.6.1 führen", + "actual": 2, + "control": "1.6.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.6.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.6.2 führen", + "actual": 2, + "control": "1.6.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "1.6.3", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 1.6.3 führen", + "actual": 2, + "control": "1.6.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "2.1.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 2.1.1 führen", + "actual": 2, + "control": "2.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "2.1.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 2.1.2 führen", + "actual": 2, + "control": "2.1.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "2.1.3", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 2.1.3 führen", + "actual": 2, + "control": "2.1.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "2.1.4", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 2.1.4 führen", + "actual": 2, + "control": "2.1.4", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "3.1.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 3.1.1 führen", + "actual": 2, + "control": "3.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "3.1.4", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 3.1.4 führen", + "actual": 2, + "control": "3.1.4", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "4.1.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 4.1.1 führen", + "actual": 2, + "control": "4.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "4.1.2", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 4.1.2 führen", + "actual": 2, + "control": "4.1.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "4.1.3", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 4.1.3 führen", + "actual": 2, + "control": "4.1.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "4.2.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 4.2.1 führen", + "actual": 2, + "control": "4.2.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.1.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.1.1 führen", + "actual": 2, + "control": "5.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.1.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.1.2 führen", + "actual": 2, + "control": "5.1.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.1 führen", + "actual": 2, + "control": "5.2.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.2", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.2 führen", + "actual": 2, + "control": "5.2.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.3", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.3 führen", + "actual": 2, + "control": "5.2.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.4", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.4 führen", + "actual": 2, + "control": "5.2.4", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.5", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.5 führen", + "actual": 2, + "control": "5.2.5", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.6", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.6 führen", + "actual": 2, + "control": "5.2.6", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.7", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.7 führen", + "actual": 2, + "control": "5.2.7", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.8", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.8 führen", + "actual": 2, + "control": "5.2.8", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.2.9", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.2.9 führen", + "actual": 2, + "control": "5.2.9", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.3.4-KI", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.3.4-KI führen", + "actual": 2, + "control": "5.3.4-KI", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.3.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.3.1 führen", + "actual": 2, + "control": "5.3.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.3.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.3.2 führen", + "actual": 2, + "control": "5.3.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.3.3", + "evidence": { + "assetLinked": true, + "implementationRule": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "fehlt" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.3.3 führen", + "actual": 2, + "control": "5.3.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "5.3.4", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 5.3.4 führen", + "actual": 2, + "control": "5.3.4", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "6.1.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 6.1.1 führen", + "actual": 2, + "control": "6.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "6.1.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 6.1.2 führen", + "actual": 2, + "control": "6.1.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "6.1.3", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 6.1.3 führen", + "actual": 2, + "control": "6.1.3", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "7.1.1", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 7.1.1 führen", + "actual": 2, + "control": "7.1.1", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + }, + { + "confirmed": null, + "control": "7.1.2", + "evidence": { + "assetLinked": true, + "operationalProof": false, + "policy": "validiert", + "riskLinked": true, + "verfahren": "validiert" + }, + "gaps": [ + { + "action": "Wirksamkeitsnachweis (Review/Audit/Test) für Control 7.1.2 führen", + "actual": 2, + "control": "7.1.2", + "kind": "nachweis", + "missing": "operativer Wirksamkeitsnachweis (aktuell)", + "target": 3 + } + ], + "suggestion": { + "reason": "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert.", + "rule": "R2", + "value": 2 + }, + "target": 3 + } + ], + "count": 45, + "level": "AL2" +} diff --git a/scripts/sync-policy-templates.ts b/scripts/sync-policy-templates.ts new file mode 100644 index 0000000..737d16d --- /dev/null +++ b/scripts/sync-policy-templates.ts @@ -0,0 +1,58 @@ +// Einmalige Synchronisierung des Datei-Vorlagenpakets in die globale DB-Vorlagenablage. +// Überführt seed/isms-vorlagenpaket-v2/ (deutsch) in eine veröffentlichte +// PolicyTemplateVersion. Danach ist die DB die Master-Quelle; der Plattform-Admin +// bearbeitet Vorlagen/Versionen dort, der Mandanten-Import liest die veröffentlichte +// Version. Idempotent: erneuter Lauf ersetzt die deutschen Inhalte der Version. +// +// Lauf (lokal): npx tsx scripts/sync-policy-templates.ts +// Lauf (Deploy): im Container/Coolify mit gesetzter DATABASE_URL ausführen (einmalig +// bzw. nach Paket-Updates, solange die Pflege noch datei-basiert erfolgt). + +import "dotenv/config"; +import { join } from "node:path"; +import { existsSync } from "node:fs"; +import { PrismaClient, type Framework } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { parsePackageFiles, mappingFileFor } from "../prisma/import-policies"; +import { syncTemplatesFromParsed } from "../prisma/template-store"; + +const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) }); +const ROOT = join(process.cwd(), "seed"); +// Sprache → Seed-Verzeichnis. EN nur, wenn vorhanden (Übersetzungspaket). +const SOURCES: Array<{ locale: string; dir: string }> = [ + { locale: "de", dir: join(ROOT, "isms-vorlagenpaket-v2") }, + { locale: "en", dir: join(ROOT, "isms-vorlagenpaket-v2-en") }, +]; +// AP1: beide Frameworks teilen den Dokumentensatz, nur das Mapping wechselt. Ein Sync +// je (Framework × Sprache) — das ISO-Mapping nur, wenn die Datei existiert. +const FRAMEWORKS: Framework[] = ["TISAX", "ISO_27001"]; + +async function main() { + for (const { locale, dir } of SOURCES) { + if (!existsSync(dir)) { + console.log(`Sprache ${locale}: kein Verzeichnis (${dir}) — übersprungen.`); + continue; + } + for (const framework of FRAMEWORKS) { + const mappingFile = mappingFileFor(framework); + if (!existsSync(join(dir, mappingFile))) { + console.log(` ${framework}/${locale}: kein ${mappingFile} — übersprungen.`); + continue; + } + const pkg = parsePackageFiles(dir, mappingFile); + const { version } = await syncTemplatesFromParsed(prisma, pkg, locale, framework, { publish: true }); + console.log( + `Vorlagen-Sync (${framework}/${locale}) → Version ${version}: ` + + `${pkg.documents.length} Dokumente, ${pkg.requirements.length} Anforderungen, ` + + `${pkg.variables.length} Variablen, ${pkg.baseline.length} Baseline, ${pkg.evidence.length} Nachweise.`, + ); + } + } +} + +main() + .catch((e) => { + console.error("Vorlagen-Sync fehlgeschlagen:", e.message); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/sync-role-permissions.ts b/scripts/sync-role-permissions.ts new file mode 100644 index 0000000..1277f87 --- /dev/null +++ b/scripts/sync-role-permissions.ts @@ -0,0 +1,79 @@ +// Rollen-Rechte-Sync (Wartung): gleicht die Rollen→Rechte-Zuordnung ALLER bestehenden +// Mandanten mit dem aktuellen Rechtekatalog (ROLE_DEFS) ab. Nötig, weil Rechte bei der +// Provisionierung in die DB geschrieben werden — neu hinzugekommene Rechte (z. B. +// `onboarding:use`, `validate_objects`) fehlen bestehenden Mandanten sonst, bis dieses +// Skript läuft. Rein additiv (entfernt keine bestehenden Zuordnungen). +// +// Lauf (lokal): npx tsx scripts/sync-role-permissions.ts +// Lauf (Deploy): im Container/Coolify mit gesetzter DATABASE_URL ausführen. +// WICHTIG: Betroffene Nutzer müssen sich danach neu einloggen (Rechte werden im JWT +// beim Login aufgelöst). + +import "dotenv/config"; // lädt DATABASE_URL aus .env beim lokalen `npx tsx`-Lauf +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { PERMISSIONS, ROLE_DEFS } from "../src/server/rbac"; + +const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) }); + +async function main() { + // 1. Globalen Rechtekatalog sicherstellen. + for (const key of PERMISSIONS) { + await prisma.permission.upsert({ where: { key }, update: {}, create: { key } }); + } + const permByKey = new Map((await prisma.permission.findMany()).map((p) => [p.key, p.id])); + + // 2. Fehlende ROLE_DEFS-Rollen je Mandant anlegen (z. B. neue Rolle „pm"). + const tenants = await prisma.tenant.findMany({ select: { id: true } }); + let createdRoles = 0; + for (const tenant of tenants) { + for (const [key, def] of Object.entries(ROLE_DEFS)) { + const existing = await prisma.role.findUnique({ where: { tenantId_key: { tenantId: tenant.id, key } } }); + if (!existing) { + await prisma.role.create({ data: { tenantId: tenant.id, key, name: def.name } }); + createdRoles++; + console.log(` ${tenant.id}: Rolle „${key}" angelegt`); + } + } + } + + // 3. Alle Rollen (mandantenübergreifend) gegen ROLE_DEFS abgleichen (Rechte + Name). + const roles = await prisma.role.findMany({ include: { rolePermissions: true } }); + let addedTotal = 0; + let touchedRoles = 0; + + for (const role of roles) { + const def = ROLE_DEFS[role.key as keyof typeof ROLE_DEFS]; + if (!def) continue; // unbekannte/manuelle Rolle unangetastet lassen + const have = new Set(role.rolePermissions.map((rp) => rp.permissionId)); + const missing = def.permissions.filter((k) => { + const id = permByKey.get(k); + return id && !have.has(id); + }); + if (missing.length === 0) continue; + + for (const key of missing) { + const permissionId = permByKey.get(key)!; + await prisma.rolePermission.upsert({ + where: { roleId_permissionId: { roleId: role.id, permissionId } }, + update: {}, + create: { roleId: role.id, permissionId }, + }); + } + // Rollenname ebenfalls aktualisieren (falls in ROLE_DEFS geändert). + if (role.name !== def.name) await prisma.role.update({ where: { id: role.id }, data: { name: def.name } }); + + addedTotal += missing.length; + touchedRoles++; + console.log(` ${role.tenantId}/${role.key}: +${missing.length} Recht(e) [${missing.join(", ")}]`); + } + + console.log(`\nFertig: ${createdRoles} Rolle(n) neu angelegt, ${addedTotal} Zuordnung(en) über ${touchedRoles} Rolle(n) ergänzt. Betroffene Nutzer bitte neu einloggen.`); +} + +main() + .catch((e) => { + console.error("Sync fehlgeschlagen:", e.message); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/test-action-error.ts b/scripts/test-action-error.ts new file mode 100644 index 0000000..2ef5d85 --- /dev/null +++ b/scripts/test-action-error.ts @@ -0,0 +1,99 @@ +// Test der Error-Boundary `withActionErrors` (Sicherheitsbefund F-16). +// +// Prüft: +// 1. Bei `ForbiddenError` wirft die Boundary nach außen die GENERISCHE Meldung +// ("Vorgang nicht möglich.") — kein Leak interner Details ("Fehlende +// Berechtigung: …"). +// 2. Intern wird der denied-Pfad genommen: ein Audit-Eintrag `action:"denied"` +// landet für Mandant + Entität in der DB. +// 3. Ein generischer Fehler wird ebenfalls generisch gekappt, aber NICHT +// auditiert (keine Zugriffsverweigerung). +// 4. Der Erfolgsfall reicht den Rückgabewert unverändert durch. +// +// Lauf: npx tsx scripts/test-action-error.ts +// Nutzt die lokale Postgres-DB (wie test-tenant-isolation.ts); .env liegt im Worktree. + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { withActionErrors, GENERIC_ACTION_ERROR } from "../src/server/action-error"; +import { ForbiddenError, type Permission } from "../src/server/rbac"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const SLUG = "zz-actionerr-test"; +const ENTITY = "risk_ae_test"; + +async function cleanup() { + const tenant = await prisma.tenant.findFirst({ + where: { slug: SLUG }, + select: { id: true }, + }); + if (tenant) { + await prisma.auditLog.deleteMany({ where: { tenantId: tenant.id } }); + await prisma.tenant.deleteMany({ where: { id: tenant.id } }); + } +} + +async function main() { + await cleanup(); + const tenant = await prisma.tenant.create({ + data: { name: "AE-Test", slug: SLUG }, + }); + const ctx = { tenantId: tenant.id, actorId: undefined, entity: ENTITY }; + + // (1) + (2) ForbiddenError → generische Meldung + denied-Audit. + let outward = ""; + try { + await withActionErrors(async () => { + throw new ForbiddenError("risk:write" as Permission); + }, ctx); + } catch (e) { + outward = e instanceof Error ? e.message : String(e); + } + ok(outward === GENERIC_ACTION_ERROR, `ForbiddenError → nach außen "${GENERIC_ACTION_ERROR}"`); + ok( + !/Fehlende Berechtigung/.test(outward), + "ForbiddenError → interne Meldung leakt NICHT nach außen", + ); + + const deniedRows = await prisma.auditLog.findMany({ + where: { tenantId: tenant.id, entity: ENTITY, action: "denied" }, + }); + ok(deniedRows.length === 1, `denied-Audit geschrieben (gefunden: ${deniedRows.length})`); + + // (3) Generischer Fehler → generisch gekappt, KEIN zusätzliches Audit. + let outward2 = ""; + try { + await withActionErrors(async () => { + throw new Error("interne DB-Details XYZ"); + }, ctx); + } catch (e) { + outward2 = e instanceof Error ? e.message : String(e); + } + ok(outward2 === GENERIC_ACTION_ERROR, "generischer Fehler → generisch gekappt"); + ok(!/XYZ/.test(outward2), "generischer Fehler → interne Details leaken NICHT"); + const afterRows = await prisma.auditLog.count({ + where: { tenantId: tenant.id, entity: ENTITY, action: "denied" }, + }); + ok(afterRows === 1, `kein zusätzliches denied-Audit für generischen Fehler (weiterhin ${afterRows})`); + + // (4) Erfolgsfall reicht Rückgabewert durch. + const result = await withActionErrors(async () => 42, ctx); + ok(result === 42, "Erfolgsfall → Rückgabewert unverändert durchgereicht"); + + await cleanup(); + + console.log(failures === 0 ? "\nOK" : `\nFEHLGESCHLAGEN (${failures})`); + await prisma.$disconnect(); + process.exit(failures === 0 ? 0 : 1); +} + +main().catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); +}); diff --git a/scripts/test-action-guard-authz.ts b/scripts/test-action-guard-authz.ts new file mode 100644 index 0000000..607d97f --- /dev/null +++ b/scripts/test-action-guard-authz.ts @@ -0,0 +1,132 @@ +// Nachweis der autoritativen Rechte-/Statusprüfung im moduleGuard (Sicherheitsbefund F-06). +// +// Der moduleGuard prüft Kontostatus, Passwortzwang und effektive Rechte NICHT mehr +// aus dem JWT, sondern autoritativ aus der Datenbank (src/server/action-guard.ts). +// Dieser Test repliziert die exakte autoritative Query und weist nach, dass die +// Guard-Entscheidung korrekt kippt, sobald sich der DB-Zustand ändert — ohne dass +// ein neues Login (Token) nötig wäre. (Ein direkter moduleGuard-Aufruf würde eine +// NextAuth-Session voraussetzen; die sicherheitsrelevante Logik ist die Query.) +// +// Lauf: npx tsx scripts/test-action-guard-authz.ts +// Nutzt die lokale Postgres-DB (Container isms-tool-postgres-1); .env liegt im Worktree. + +import "dotenv/config"; +import { prisma } from "../src/server/db"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const SLUG = "zz-f06-authz-test"; +const EMAIL = "f06-user@zz-authz.test"; +const PERM = "asset:write"; // existiert im globalen Permissionskatalog + +/** + * Repliziert die autoritative Prüfung aus moduleGuard (Option C): Membership-Status + + * effektive Rechte kommen aus `User`, Passwortzwang + globaler Status aus der `Identity`. + * Liefert `null`, wenn Mitgliedschaft ODER Identity nicht (mehr) aktiv ist. + */ +async function authorize(userId: string, identityId: string): Promise<{ mustChangePassword: boolean; perms: Set } | null> { + const account = await prisma.user.findFirst({ + where: { id: userId, status: "ACTIVE" }, + select: { + userRoles: { + select: { + role: { + select: { + rolePermissions: { select: { permission: { select: { key: true } } } }, + }, + }, + }, + }, + }, + }); + const identity = await prisma.identity.findUnique({ + where: { id: identityId }, + select: { status: true, mustChangePassword: true }, + }); + if (!account || !identity || identity.status !== "ACTIVE") return null; + return { + mustChangePassword: identity.mustChangePassword, + perms: new Set(account.userRoles.flatMap((ur) => ur.role.rolePermissions.map((rp) => rp.permission.key))), + }; +} + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG } }); + if (!t) return; + await prisma.user.deleteMany({ where: { tenantId: t.id } }); + await prisma.role.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); + // Verwaiste Test-Identity(s) entfernen (Membership wurde eben gelöscht). + await prisma.identity.deleteMany({ where: { email: EMAIL, memberships: { none: {} } } }); +} + +async function main() { + await cleanup(); + + const tenant = await prisma.tenant.create({ data: { name: "F06 AuthZ Test", slug: SLUG } }); + const perm = await prisma.permission.findFirstOrThrow({ where: { key: PERM } }); + const role = await prisma.role.create({ + data: { + tenantId: tenant.id, + key: "f06-role", + name: "F06 Rolle", + rolePermissions: { create: [{ permissionId: perm.id }] }, + }, + }); + // Option C: Mitgliedschaft braucht eine globale Identity (Anmeldung). + const identity = await prisma.identity.create({ data: { email: EMAIL, passwordHash: "x" } }); + const user = await prisma.user.create({ + data: { + tenantId: tenant.id, + identityId: identity.id, + email: EMAIL, + name: "F06 User", + status: "ACTIVE", + userRoles: { create: [{ roleId: role.id }] }, + }, + }); + + // (1) Aktives Konto mit Recht → Guard ließe die Mutation zu. + const a1 = await authorize(user.id, identity.id); + ok(a1 !== null, "(1) aktives Konto wird gefunden"); + ok(a1?.perms.has(PERM) === true, `(1) effektive Rechte enthalten ${PERM}`); + ok(a1?.perms.has("risk:accept") === false, "(1) nicht vergebenes Recht fehlt korrekt"); + + // (2) Membership deaktiviert → Query liefert null → Guard wirft „Konto ist nicht aktiv". + await prisma.user.update({ where: { id: user.id }, data: { status: "DEACTIVATED" } }); + const a2 = await authorize(user.id, identity.id); + ok(a2 === null, "(2) deaktivierte Mitgliedschaft → null (Mutation sofort geblockt)"); + + // (2b) Membership aktiv, aber IDENTITY deaktiviert → ebenfalls null (globale Sperre). + await prisma.user.update({ where: { id: user.id }, data: { status: "ACTIVE" } }); + await prisma.identity.update({ where: { id: identity.id }, data: { status: "DISABLED" } }); + ok((await authorize(user.id, identity.id)) === null, "(2b) deaktivierte Identity → null (globale Sperre wirkt)"); + await prisma.identity.update({ where: { id: identity.id }, data: { status: "ACTIVE" } }); + + // (3) Recht entzogen → Recht fehlt → Guard wirft ForbiddenError. + await prisma.rolePermission.delete({ where: { roleId_permissionId: { roleId: role.id, permissionId: perm.id } } }); + const a3 = await authorize(user.id, identity.id); + ok(a3 !== null, "(3) Konto aktiv"); + ok(a3?.perms.has(PERM) === false, `(3) entzogenes Recht ${PERM} sofort weg (kein Warten auf neues Login)`); + + // (4) Passwortzwang an der Identity → Guard wirft „Passwortwechsel erforderlich". + await prisma.identity.update({ where: { id: identity.id }, data: { mustChangePassword: true } }); + const a4 = await authorize(user.id, identity.id); + ok(a4?.mustChangePassword === true, "(4) mustChangePassword (Identity) wird autoritativ erkannt"); + + await cleanup(); + + if (failures === 0) console.log("\nOK — alle F-06-Nachweise (1)-(4) erfüllt."); + else console.log(`\n${failures} FEHLER.`); + process.exit(failures === 0 ? 0 : 1); +} + +main().catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + process.exit(1); +}); diff --git a/scripts/test-assessment-iso.ts b/scripts/test-assessment-iso.ts new file mode 100644 index 0000000..2b55873 --- /dev/null +++ b/scripts/test-assessment-iso.ts @@ -0,0 +1,60 @@ +// B1 Schritt 5/6 — ISO-Bewertung über buildAssessment("ISO_27001"). Prüft Scope (SoA- +// Anwendbarkeit + Klauseln 4–10), Umsetzungsgrad-Kennzahl, leere-SoA-Hinweis und dass +// KEIN TISAX-Vokabular (Reifegrad/AL) in der ISO-Zusammenfassung auftaucht. +// +// Lauf: npx tsx scripts/test-assessment-iso.ts + +import "dotenv/config"; +import { prisma, dbForTenant } from "../src/server/db"; +import { buildAssessment } from "../src/server/assessment"; +import { ensureSoaEntries } from "../src/server/soa-statement"; + +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; +const SLUG = "b1-test-iso"; + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG }, select: { id: true } }); + if (!t) return; + await prisma.soaEntry.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); +} + +async function main() { + await cleanup(); + const tenant = await prisma.tenant.create({ data: { name: "B1 ISO", slug: SLUG } }); + const t = tenant.id; + const db = dbForTenant(t); + + // ── A) Leere SoA → „Anwendbarkeit offen", nicht 0 % ───────────────────────── + const empty = await buildAssessment(db, t, "ISO_27001"); + ok(empty.summary.band === "Anwendbarkeit offen" && empty.summary.metricValue === "—", "leere SoA meldet Anwendbarkeit-noch-nicht-erklaert (nicht 0 Prozent)"); + + // ── B) SoA vorbefüllen → Bewertung rechnet ────────────────────────────────── + await ensureSoaEntries(db, t); + const asm = await buildAssessment(db, t, "ISO_27001"); + const clauses = asm.rows.filter((r) => !r.control.startsWith("A.")); + const annex = asm.rows.filter((r) => r.control.startsWith("A.")); + ok(clauses.length >= 20, `Klauseln 4–10 immer im Scope (${clauses.length})`); + ok(annex.length > 0, `anwendbare Annex-A-Controls im Scope (${annex.length})`); + ok(asm.rows.every((r) => r.verdict.kind === "status"), "jede ISO-Bewertung ist ein Status-Verdict (kein Reifegrad)"); + ok(asm.summary.metricLabel === "Umsetzungsgrad" && asm.summary.metricValue.endsWith("%"), `Kennzahl ist der Umsetzungsgrad (${asm.summary.metricValue})`); + + // ── C) Einige anwendbare Controls „umgesetzt" → fulfilled steigt ──────────── + const applicableAnnex = await prisma.soaEntry.findMany({ where: { tenantId: t, framework: "ISO_27001", applicable: true }, select: { id: true }, take: 5 }); + await prisma.soaEntry.updateMany({ where: { id: { in: applicableAnnex.map((s) => s.id) } }, data: { implementationStatus: "umgesetzt" } }); + const asm2 = await buildAssessment(db, t, "ISO_27001"); + ok(asm2.summary.fulfilled >= 5, `bestätigte Umsetzungen zählen in den Umsetzungsgrad (${asm2.summary.fulfilled} umgesetzt)`); + + // ── Kein TISAX-Vokabular in der ISO-Sicht ─────────────────────────────────── + const vocab = `${asm2.summary.band} ${asm2.summary.metricLabel} ${asm2.summary.text}`; + ok(!/Reifegrad|AL2|AL3|Prüfziel|Assessment-reif/.test(vocab), "keine Reifegrad-/AL-/Prüfziel-Begriffe in der ISO-Zusammenfassung"); + + await cleanup(); + console.log("\n✓ aufgeräumt (Wegwerf-Mandant entfernt)"); +} + +main() + .then(() => { console.log(failures === 0 ? "\nISO-Bewertung grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch(async (e) => { console.error(e); await cleanup().catch(() => {}); process.exit(1); }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/test-auth-selfservice.ts b/scripts/test-auth-selfservice.ts new file mode 100644 index 0000000..c174d4d --- /dev/null +++ b/scripts/test-auth-selfservice.ts @@ -0,0 +1,170 @@ +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { consumeToken, issueToken, peekToken, purgeExpiredTokens } from "../src/server/auth-token"; +import { isTokenStillValid } from "../src/server/sessions"; +import { checkRateLimit, RATE_LIMITS, resetRateLimits } from "../src/server/rate-limit"; +import { findAccountByEmail } from "../src/server/auth-selfservice"; +import { closeQueues } from "../src/server/mail/queue"; +import { closeMailProvider } from "../src/server/mail/provider-smtp"; + +/** + * SEC2 — Abnahmetest der Sicherheitseigenschaften + * (`npx tsx scripts/test-auth-selfservice.ts`). + * + * Geprüft wird, was sich ohne Browser prüfen lässt — die eigentlichen + * Sicherheitsgarantien: + * 1. Token: nur der Hash liegt in der DB, nie das Rohtoken. + * 2. Single-use: zweite Einlösung schlägt fehl. + * 3. Ablauf: abgelaufene Tokens werden abgewiesen. + * 4. Neuanforderung entwertet den vorherigen Link. + * 5. Manipuliertes/unbekanntes Token wird abgewiesen. + * 6. Typ-Verwechslung (email_change als password_reset) wird abgewiesen. + * 7. Rate-Limit greift je IP und je Konto. + * 8. Session-Invalidierung: älteres JWT ungültig, neueres gültig. + * 9. Enumeration: unbekannte Adresse liefert kein Konto. + * + * Die Browser-Abläufe (Reset-Mail → Link → neues Passwort) stehen im Testplan + * von docs/SEC2-AUTH-SELFSERVICE.md. + */ + +let failures = 0; +function check(name: string, ok: boolean, detail?: string) { + if (ok) console.log(` ✓ ${name}`); + else { + failures++; + console.error(` ✗ ${name}${detail ? ` — ${detail}` : ""}`); + } +} + +const PRINCIPAL = "sec2-test-principal"; + +async function cleanup() { + await prisma.authToken.deleteMany({ where: { principalId: { startsWith: PRINCIPAL } } }); +} + +async function main() { + await cleanup(); + resetRateLimits(); + + console.log("1) Token wird nur gehasht gespeichert"); + const t1 = await issueToken({ + principalType: "tenant_user", + principalId: `${PRINCIPAL}-1`, + tenantId: null, + type: "password_reset", + }); + const rows = await prisma.authToken.findMany({ where: { principalId: `${PRINCIPAL}-1` } }); + check("genau ein Token angelegt", rows.length === 1); + check("Rohtoken steht NICHT in der DB", !rows.some((r) => r.tokenHash === t1.raw)); + check("Hash ist 64 Hex-Zeichen (SHA-256)", /^[0-9a-f]{64}$/.test(rows[0]?.tokenHash ?? "")); + check("Rohtoken ist ausreichend lang", t1.raw.length >= 40, `${t1.raw.length} Zeichen`); + + console.log("2) Single-use"); + const first = await consumeToken(t1.raw, "password_reset"); + check("erste Einlösung erfolgreich", first != null); + const second = await consumeToken(t1.raw, "password_reset"); + check("zweite Einlösung abgewiesen", second === null); + check("peek nach Verbrauch liefert null", (await peekToken(t1.raw, "password_reset")) === null); + + console.log("3) Ablauf"); + const t2 = await issueToken({ + principalType: "tenant_user", + principalId: `${PRINCIPAL}-2`, + type: "password_reset", + }); + await prisma.authToken.updateMany({ + where: { principalId: `${PRINCIPAL}-2` }, + data: { expiresAt: new Date(Date.now() - 1000) }, + }); + check("abgelaufenes Token abgewiesen", (await peekToken(t2.raw, "password_reset")) === null); + + console.log("4) Neuanforderung entwertet den vorherigen Link"); + const t3a = await issueToken({ + principalType: "tenant_user", + principalId: `${PRINCIPAL}-3`, + type: "password_reset", + }); + const t3b = await issueToken({ + principalType: "tenant_user", + principalId: `${PRINCIPAL}-3`, + type: "password_reset", + }); + check("alter Link ungültig", (await peekToken(t3a.raw, "password_reset")) === null); + check("neuer Link gültig", (await peekToken(t3b.raw, "password_reset")) != null); + + console.log("5) Unbekanntes/manipuliertes Token"); + check("Zufallswert abgewiesen", (await peekToken("nicht-existent-xyz", "password_reset")) === null); + check("leeres Token abgewiesen", (await peekToken("", "password_reset")) === null); + check( + "manipuliertes Token abgewiesen", + (await peekToken(t3b.raw.slice(0, -2) + "AA", "password_reset")) === null, + ); + + console.log("6) Typ-Verwechslung"); + const t4 = await issueToken({ + principalType: "tenant_user", + principalId: `${PRINCIPAL}-4`, + type: "email_change", + newEmail: "neu@example.test", + }); + check("email_change nicht als password_reset einlösbar", (await peekToken(t4.raw, "password_reset")) === null); + check("email_change als email_change gültig", (await peekToken(t4.raw, "email_change")) != null); + + console.log("7) Rate-Limit"); + resetRateLimits(); + const rule = RATE_LIMITS.passwordResetRequest; + let blockedAt = -1; + for (let i = 1; i <= rule.limit + 2; i++) { + const r = checkRateLimit("passwordResetRequest", { ip: "203.0.113.9", account: "a@example.test" }); + if (!r.allowed && blockedAt < 0) blockedAt = i; + } + check(`greift nach ${rule.limit} Versuchen`, blockedAt === rule.limit + 1, `blockiert ab ${blockedAt}`); + const otherIp = checkRateLimit("passwordResetRequest", { ip: "198.51.100.4", account: "b@example.test" }); + check("anderes Konto/IP unberührt", otherIp.allowed); + const sameAccountOtherIp = checkRateLimit("passwordResetRequest", { + ip: "198.51.100.5", + account: "a@example.test", + }); + check("Kontozähler greift auch von anderer IP", !sameAccountOtherIp.allowed); + + console.log("8) Session-Invalidierung"); + const mark = new Date("2026-07-30T12:00:00Z"); + const before = Math.floor(mark.getTime() / 1000) - 10; + const after = Math.floor(mark.getTime() / 1000) + 10; + check("älteres JWT ungültig", !isTokenStillValid(before, mark)); + check("neueres JWT gültig", isTokenStillValid(after, mark)); + check("ohne Marke immer gültig", isTokenStillValid(before, null)); + check("ohne iat fail-closed", !isTokenStillValid(undefined, mark)); + + console.log("9) Enumeration"); + check( + "unbekannte Adresse liefert kein Konto", + (await findAccountByEmail("tenant", `nichtda-${Date.now()}@example.test`)) === null, + ); + check( + "unbekannter Plattform-Admin liefert kein Konto", + (await findAccountByEmail("platform", `nichtda-${Date.now()}@example.test`)) === null, + ); + + console.log("10) Aufräumen abgelaufener Tokens"); + const purged = await purgeExpiredTokens(); + check("purge läuft durch", purged >= 0, `${purged} entfernt`); + + await cleanup(); + await prisma.$disconnect(); + await closeMailProvider(); + await closeQueues(); + + if (failures > 0) { + console.error(`\n✗ ${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(1); + } + console.log("\n✓ SEC2-Self-Service: alle Prüfungen bestanden."); + process.exit(0); +} + +main().catch(async (err) => { + console.error(err); + await prisma.$disconnect().catch(() => {}); + process.exit(1); +}); diff --git a/scripts/test-backup-download.ts b/scripts/test-backup-download.ts new file mode 100644 index 0000000..0ff443d --- /dev/null +++ b/scripts/test-backup-download.ts @@ -0,0 +1,29 @@ +// Direkt-Download-Pfad: exportTenant(persist:false) liefert das verschlüsselte +// Artefakt als Buffer OHNE Store-Roundtrip (Grundlage der /api/platform/backup/download-Route). +// Lauf: npx tsx scripts/test-backup-download.ts (nutzt lokale isms-DB) +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { exportTenant } from "../src/server/backup/export"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function main() { + const demo = await prisma.tenant.findFirst({ where: { slug: "demo" }, select: { id: true } }); + if (!demo) throw new Error("Mandant 'demo' fehlt — bitte seeden."); + + const res = await exportTenant(demo.id, { persist: false }); + ok(res.artifact.length > 1000, `Artefakt hat Bytes (${res.artifact.length})`); + ok(res.artifact.subarray(0, 4).toString("utf8") === "CVB1", `verschlüsselter Kopf „CVB1" (hex ${res.artifact.subarray(0, 4).toString("hex")})`); + ok(res.artifactKey === null, "persist:false → NICHT im Store abgelegt (artifactKey === null)"); + ok((res.manifest.totalRows ?? 0) > 0, `Manifest: Zeilen > 0 (${res.manifest.totalRows})`); + ok(res.snapshotId.length > 0, `snapshotId für den Dateinamen vorhanden (${res.snapshotId})`); + + await prisma.$disconnect(); + console.log(failures === 0 ? "\nAlle grün." : `\n${failures} FEHLER`); + process.exit(failures === 0 ? 0 : 1); +} +main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/scripts/test-backup-dsgvo.ts b/scripts/test-backup-dsgvo.ts new file mode 100644 index 0000000..fb24acc --- /dev/null +++ b/scripts/test-backup-dsgvo.ts @@ -0,0 +1,118 @@ +// DSGVO-Grundgerüst: Auskunft (Art. 15/20), Löschung/Anonymisierung (Art. 17) +// und der restore-feste Tombstone (KONZEPT §6). Arbeitet auf einem WEGWERF- +// Mandanten (Slug zz-dsgvo-*) — demo/demo2 bleiben unberührt. +// +// Lauf: npx tsx scripts/test-backup-dsgvo.ts + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { exportTenant } from "../src/server/backup/export"; +import { restoreTenant } from "../src/server/backup/restore"; +import { exportSubject } from "../src/server/dsgvo/export"; +import { deleteSubject } from "../src/server/dsgvo/deletion"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const SLUG = "zz-dsgvo-test"; +const EMAIL = "zz-dsgvo-person@example.test"; + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG }, select: { id: true } }); + const identityIds = new Set(); + if (t) { + for (const u of await prisma.user.findMany({ where: { tenantId: t.id }, select: { identityId: true } })) { + identityIds.add(u.identityId); + } + await prisma.tombstoneEntry.deleteMany({ where: { tenantId: t.id } }); + await prisma.deletionCertificate.deleteMany({ where: { tenantId: t.id } }); + await prisma.auditLog.deleteMany({ where: { tenantId: t.id } }); + await prisma.asset.deleteMany({ where: { tenantId: t.id } }); + await prisma.userRole.deleteMany({ where: { user: { tenantId: t.id } } }); + await prisma.user.deleteMany({ where: { tenantId: t.id } }); + await prisma.role.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); + } + // Identity per E-Mail (frischer Lauf) UND per gesammelter Id (ggf. schon anonymisiert). + const byEmail = await prisma.identity.findUnique({ where: { email: EMAIL }, select: { id: true } }); + if (byEmail) identityIds.add(byEmail.id); + for (const id of identityIds) { + if ((await prisma.user.count({ where: { identityId: id } })) === 0) { + await prisma.identity.delete({ where: { id } }).catch(() => {}); + } + } +} + +async function main() { + await cleanup(); + + // Fixture: Mandant + Identity + Mitgliedschaft + Rolle + Asset + AuditLog. + const tenant = await prisma.tenant.create({ data: { name: "DSGVO Test", slug: SLUG } }); + const identity = await prisma.identity.create({ + data: { email: EMAIL, passwordHash: "x", status: "ACTIVE" }, + }); + const user = await prisma.user.create({ + data: { tenantId: tenant.id, identityId: identity.id, email: EMAIL, name: "Test Person" }, + }); + const role = await prisma.role.create({ data: { tenantId: tenant.id, key: "member", name: "Member" } }); + await prisma.userRole.create({ data: { userId: user.id, roleId: role.id } }); + await prisma.asset.create({ + data: { tenantId: tenant.id, name: "Server der Person", type: "SYSTEM", ownerId: user.id, createdBy: user.id }, + }); + await prisma.auditLog.create({ + data: { tenantId: tenant.id, actorId: user.id, action: "create", entity: "asset" }, + }); + + // 1. Auskunft (Art. 15/20). + const subj = await exportSubject(tenant.id, identity.id); + ok(subj.identity?.email === EMAIL, "Auskunft enthält Identity-Metadaten (E-Mail)"); + ok(!("passwordHash" in (subj.identity ?? {})), "Auskunft enthält KEINE Secrets (passwordHash)"); + ok(subj.memberships.length === 1, "Auskunft enthält die Mitgliedschaft"); + ok(!!subj.references["Asset.ownerId"], "Auskunft findet Asset über ownerId"); + ok(!!subj.references["AuditLog.actorId"], "Auskunft findet AuditLog über actorId"); + + // Snapshot MIT Original-PII (für den Tombstone-on-Restore-Beweis). + const snap = await exportTenant(tenant.id, { persist: false, reason: "dsgvo-test" }); + + // 2. Löschung/Anonymisierung (Art. 17). + const del = await deleteSubject(tenant.id, identity.id, { reason: "test" }); + ok(del.anonymizedMemberships === 1, "Löschung anonymisiert die Mitgliedschaft"); + ok(del.identityAnonymized, "Globale Identity anonymisiert (keine Rest-Mitgliedschaft)"); + + const userAfter = await prisma.user.findUnique({ where: { id: user.id } }); + ok(userAfter?.name === "Gelöschte Person" && userAfter?.email !== EMAIL, "User-Zeile ist anonymisiert (Name/E-Mail Tombstone)"); + const idnAfter = await prisma.identity.findUnique({ where: { id: identity.id } }); + ok(idnAfter?.email !== EMAIL && idnAfter?.status === "DISABLED", "Identity anonymisiert + DISABLED"); + + const cert = await prisma.deletionCertificate.findUnique({ where: { id: del.certificateId } }); + ok(cert?.scope === "person", "Löschnachweis (DeletionCertificate) erstellt"); + const tomb = await prisma.tombstoneEntry.findFirst({ where: { tenantId: tenant.id, model: "User", targetValue: user.id } }); + ok(tomb?.action === "anonymize", "Tombstone-Eintrag gesetzt (restore-fest)"); + + // 3. BEWEIS Tombstone-on-Restore: alter Snapshot bringt PII NICHT zurück. + const res = await restoreTenant(tenant.id, { artifact: snap.artifact, manifest: snap.manifest }, { skipPreRestore: true }); + ok(res.tombstonesReapplied >= 1, `Restore wendet Tombstones erneut an (${res.tombstonesReapplied})`); + const userReborn = await prisma.user.findUnique({ where: { id: user.id } }); + ok(userReborn != null, "User-Zeile nach Restore wieder vorhanden (referenzielle Struktur)"); + ok(userReborn?.name === "Gelöschte Person" && userReborn?.email !== EMAIL, "PII bleibt trotz altem Snapshot getilgt (Tombstone erneut angewandt)"); +} + +main() + .then(async () => { + await cleanup(); + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-backup-isolation.ts b/scripts/test-backup-isolation.ts new file mode 100644 index 0000000..c1cf633 --- /dev/null +++ b/scripts/test-backup-isolation.ts @@ -0,0 +1,165 @@ +// Isolationsnachweis der Backup-/Restore-Engine (destruktive Lane). +// +// Beweisziel: Export → Wipe → Restore von Mandant `demo` lässt JEDE Tabelle des +// zweiten Mandanten `demo2` (inkl. der Join-Tabellen UserRole/RolePermission) +// BIT-genau unberührt. Gemessen wird per Owner-Rowcount (BYPASSRLS) über die aus +// dem DMMF abgeleitete Traversierungs-Topologie — also über GENAU die Tabellen, +// die die Engine anfasst. +// +// Lauf: npx tsx scripts/test-backup-isolation.ts +// Nutzt die lokale isms-DB (geseedet: demo + demo2). Nach Erfolg ist `demo` +// wiederhergestellt; bei Fehlschlag ggf. `npx tsx prisma/seed.ts` nachziehen. + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { buildTenantTopology, assertTopologyMatchesDatabase } from "../src/server/backup/topology"; +import { exportTenant } from "../src/server/backup/export"; +import { restoreTenant } from "../src/server/backup/restore"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +type Fingerprint = Map; + +/** Owner-Rowcount je Modell für genau einen Mandanten (Join-Tabellen via id-Menge). */ +async function fingerprint(tenantId: string): Promise { + const topo = buildTenantTopology(); + const fp: Fingerprint = new Map(); + // id-Mengen der scopenden Elternteile (User/Role) einmal bestimmen. + const idSets = new Map(); + for (const node of topo.insertOrder) { + const delegate = (prisma as unknown as Record Promise; + findMany: (a: unknown) => Promise[]>; + }>)[node.delegate]; + + let count: number; + if (node.scope.by === "tenantColumn") { + count = await delegate.count({ where: { tenantId } }); + if (node.pk.length === 1) { + const rows = await delegate.findMany({ where: { tenantId }, select: { [node.pk[0]]: true } }); + idSets.set(node.model, rows.map((r) => String(r[node.pk[0]]))); + } + } else { + const via = node.scope.via; + const ids = idSets.get(via.parent) ?? []; + count = ids.length + ? await delegate.count({ where: { [via.fromFields[0]]: { in: ids } } }) + : 0; + } + fp.set(node.model, count); + } + return fp; +} + +function compare(before: Fingerprint, after: Fingerprint, adjust: Record = {}): string[] { + const diffs: string[] = []; + for (const [model, b] of before) { + const expected = b + (adjust[model] ?? 0); + const a = after.get(model) ?? -1; + if (a !== expected) diffs.push(`${model}: erwartet ${expected}, ist ${a}`); + } + return diffs; +} + +/** Destruktiver Wipe eines Mandanten (nur DB-Zeilen; Identities unangetastet). */ +async function wipeTenant(tenantId: string): Promise { + const topo = buildTenantTopology(); + await prisma.$transaction(async (tx) => { + await tx.$executeRawUnsafe(`SET LOCAL session_replication_role = replica`); + for (const node of topo.deleteOrder) { + const del = (tx as unknown as Record Promise<{ count: number }>; + findMany: (a: unknown) => Promise[]>; + }>)[node.delegate]; + if (node.scope.by === "tenantColumn") { + await del.deleteMany({ where: { tenantId } }); + } else { + const via = node.scope.via; + const parentNode = topo.nodes.get(via.parent)!; + const parentPk = parentNode.pk[0]; + const parentDelegate = (tx as unknown as Record Promise[]>; + }>)[parentNode.delegate]; + const parents = await parentDelegate.findMany({ where: { tenantId }, select: { [parentPk]: true } }); + const ids = parents.map((p) => String(p[parentPk])); + if (ids.length) await del.deleteMany({ where: { [via.fromFields[0]]: { in: ids } } }); + } + } + }); +} + +async function main() { + // 0. Topologie-Selbstnachweis: abgeleitete FK-Ordnung == reale DB-Constraints. + await assertTopologyMatchesDatabase(prisma); + ok(true, "Topologie deckt sich mit den DB-FK-Constraints (fail-closed-Prüfung bestanden)"); + + const demo = await prisma.tenant.findUnique({ where: { slug: "demo" }, select: { id: true } }); + const demo2 = await prisma.tenant.findUnique({ where: { slug: "demo2" }, select: { id: true } }); + if (!demo || !demo2) { + console.error("demo/demo2 nicht gefunden — bitte seeden (npx tsx prisma/seed.ts)."); + process.exit(1); + } + + // 1. Ausgangs-Fingerprints. + const demoBefore = await fingerprint(demo.id); + const demo2Before = await fingerprint(demo2.id); + const demoTotal = [...demoBefore.values()].reduce((a, b) => a + b, 0); + const demo2Total = [...demo2Before.values()].reduce((a, b) => a + b, 0); + ok(demoTotal > 0, `demo hat Daten (${demoTotal} Zeilen über ${demoBefore.size} Tabellen)`); + ok(demo2Total > 0, `demo2 hat Daten (${demo2Total} Zeilen über ${demo2Before.size} Tabellen)`); + // Join-Tabellen explizit sichtbar machen (Prompt-Fokus). + ok((demo2Before.get("UserRole") ?? 0) > 0, `demo2 UserRole-Zuweisungen vorhanden (${demo2Before.get("UserRole")})`); + ok((demo2Before.get("RolePermission") ?? 0) > 0, `demo2 RolePermission-Zuordnungen vorhanden (${demo2Before.get("RolePermission")})`); + + // 2. Export demo (in-memory, kein Upload nötig). + const snap = await exportTenant(demo.id, { persist: false, reason: "isolation-test" }); + ok(snap.manifest.totalRows === demoTotal, `Export demo erfasst alle Zeilen (${snap.manifest.totalRows}/${demoTotal})`); + + // 3. Wipe demo (destruktiv). + await wipeTenant(demo.id); + const demoWiped = await fingerprint(demo.id); + ok([...demoWiped.values()].every((c) => c === 0), "demo nach Wipe leer (alle Tabellen 0)"); + + // 3a. BEWEIS: demo2 nach dem demo-Wipe unverändert. + const demo2AfterWipe = await fingerprint(demo2.id); + const wipeDiffs = compare(demo2Before, demo2AfterWipe); + ok(wipeDiffs.length === 0, `demo2 nach demo-Wipe UNVERÄNDERT${wipeDiffs.length ? " — " + wipeDiffs.join("; ") : ""}`); + + // 4. Restore demo aus dem Artefakt. + const res = await restoreTenant( + demo.id, + { artifact: snap.artifact, manifest: snap.manifest }, + { skipPreRestore: true, actorId: undefined }, + ); + ok(res.restoredRows === demoTotal, `Restore demo reinsertet alle Zeilen (${res.restoredRows}/${demoTotal})`); + ok(res.stubIdentities.length === 0, "Restore demo ohne Identity-Stubs (Identities waren intakt)"); + + // 4a. demo exakt wiederhergestellt (AuditLog +1 durch den Restore-Audit-Eintrag). + const demoAfter = await fingerprint(demo.id); + const demoDiffs = compare(demoBefore, demoAfter, { AuditLog: 1 }); + ok(demoDiffs.length === 0, `demo exakt wiederhergestellt${demoDiffs.length ? " — " + demoDiffs.join("; ") : " (AuditLog +1 = Restore-Audit)"}`); + + // 4b. BEWEIS (Hauptziel): demo2 über den gesamten Restore unverändert. + const demo2After = await fingerprint(demo2.id); + const restoreDiffs = compare(demo2Before, demo2After); + ok(restoreDiffs.length === 0, `demo2 nach demo-Restore UNVERÄNDERT — JEDE Tabelle${restoreDiffs.length ? " — " + restoreDiffs.join("; ") : " (inkl. UserRole/RolePermission)"}`); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-backup-portal.ts b/scripts/test-backup-portal.ts new file mode 100644 index 0000000..adafd6c --- /dev/null +++ b/scripts/test-backup-portal.ts @@ -0,0 +1,157 @@ +// Backup-Portal-Lane: Enqueue-/Kontroll-Logik + DSGVO-Zustellpaket. +// +// Deckt OHNE laufenden BullMQ-Worker ab (KONZEPT §4-Kontrollen + §5-Zustellung): +// (1) Getippte Bestätigung „RESTORE " — exakter Match (Kontrolle 3). +// (2) MFA-Step-up mit Replay-Schutz: frischer Code ok, verbrauchter/älterer +// Zeitschritt wird abgelehnt (Kontrolle 2). +// (3) ZIP-Writer: rundläuft durch das System-`unzip` (echtes ZIP-Format). +// (4) DSGVO-Zustellpaket (Per-Person) enthält die erwarteten Einträge OHNE +// Secrets; der dsgvo_export-Job erzeugt Store-Objekt + signierten Token +// mit kurzer TTL (processBackupJob direkt, ohne Redis). +// +// Lauf: npx tsx scripts/test-backup-portal.ts (nutzt lokale isms-DB, räumt auf) + +import "dotenv/config"; +import { execFileSync } from "node:child_process"; +import { mkdtempSync, writeFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { generateSync } from "otplib"; +import { prisma } from "../src/server/db"; +import { verifyTotp, newTotpSecret } from "../src/server/mfa"; +import { matchesRestoreConfirmation, restoreConfirmationFor } from "../src/server/backup/restore-confirm"; +import { buildZip } from "../src/server/backup/zip"; +import { buildDsgvoPackage } from "../src/server/backup/dsgvo-zip"; +import { processBackupJob, dsgvoPackageKey } from "../src/server/backup/ops"; +import { getBackupStore } from "../src/server/storage/backup-store"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const SLUG = "zz-portal-test"; +const EMAIL = "zz-portal-person@example.test"; + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG }, select: { id: true } }); + const identityIds = new Set(); + if (t) { + for (const u of await prisma.user.findMany({ where: { tenantId: t.id }, select: { identityId: true } })) identityIds.add(u.identityId); + await prisma.backupJob.deleteMany({ where: { tenantId: t.id } }); + await prisma.tombstoneEntry.deleteMany({ where: { tenantId: t.id } }); + await prisma.deletionCertificate.deleteMany({ where: { tenantId: t.id } }); + await prisma.auditLog.deleteMany({ where: { tenantId: t.id } }); + await prisma.asset.deleteMany({ where: { tenantId: t.id } }); + await prisma.userRole.deleteMany({ where: { user: { tenantId: t.id } } }); + await prisma.user.deleteMany({ where: { tenantId: t.id } }); + await prisma.role.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); + await (await getBackupStore()).remove(`${t.id}/`); + } + const byEmail = await prisma.identity.findUnique({ where: { email: EMAIL }, select: { id: true } }); + if (byEmail) identityIds.add(byEmail.id); + for (const id of identityIds) { + if ((await prisma.user.count({ where: { identityId: id } })) === 0) { + await prisma.identity.delete({ where: { id } }).catch(() => {}); + } + } +} + +async function main() { + await cleanup(); + + // ── (1) Getippte Bestätigung ──────────────────────────────────────────────── + console.log("\n(1) Getippte Bestätigung „RESTORE \":"); + ok(matchesRestoreConfirmation("kunde-a", "RESTORE kunde-a"), "exakter Match akzeptiert"); + ok(!matchesRestoreConfirmation("kunde-a", "RESTORE kunde-b"), "falscher Slug abgelehnt"); + ok(!matchesRestoreConfirmation("kunde-a", "restore kunde-a"), "abweichende Groß-/Kleinschreibung abgelehnt"); + ok(!matchesRestoreConfirmation("kunde-a", " RESTORE kunde-a "), "Leerzeichen-Abweichung abgelehnt"); + ok(restoreConfirmationFor("kunde-a") === "RESTORE kunde-a", "Erwartungstext korrekt gebildet"); + + // ── (2) MFA-Step-up + Replay-Schutz ───────────────────────────────────────── + console.log("\n(2) MFA-Step-up (Replay-Schutz über lastTotpStep):"); + const secret = newTotpSecret(); + const code = generateSync({ secret }); + const first = verifyTotp(code, secret); + ok(first.ok, "frischer TOTP-Code wird akzeptiert"); + ok(!verifyTotp("000000", secret).ok, "falscher Code abgelehnt"); + if (first.ok) { + const replay = verifyTotp(code, secret, first.step); + ok(!replay.ok, "verbrauchter Zeitschritt (Replay) wird abgelehnt"); + } + + // ── (3) ZIP-Writer rundläuft durch System-unzip ──────────────────────────── + console.log("\n(3) ZIP-Writer (Standardformat):"); + const zip = buildZip([ + { name: "hello.txt", data: "Hallo Welt" }, + { name: "data/inner.json", data: JSON.stringify({ a: 1 }) }, + ]); + const dir = mkdtempSync(join(tmpdir(), "cvzip-")); + const zipPath = join(dir, "t.zip"); + writeFileSync(zipPath, zip); + let unzipOk = true; + let content = ""; + try { + const list = execFileSync("unzip", ["-l", zipPath], { encoding: "utf8" }); + unzipOk = list.includes("hello.txt") && list.includes("data/inner.json"); + content = execFileSync("unzip", ["-p", zipPath, "hello.txt"], { encoding: "utf8" }); + } catch (e) { + unzipOk = false; + console.warn(" (unzip nicht verfügbar/ Fehler:", e instanceof Error ? e.message : e, ")"); + } + ok(unzipOk, "ZIP von System-`unzip` gelesen (beide Einträge vorhanden)"); + ok(content.trim() === "Hallo Welt", "entpackter Inhalt stimmt (CRC/Deflate korrekt)"); + rmSync(dir, { recursive: true, force: true }); + + // ── Fixture-Mandant für DSGVO ────────────────────────────────────────────── + const tenant = await prisma.tenant.create({ data: { name: "Portal Test", slug: SLUG } }); + const identity = await prisma.identity.create({ data: { email: EMAIL, passwordHash: "x", status: "ACTIVE" } }); + const user = await prisma.user.create({ data: { tenantId: tenant.id, identityId: identity.id, email: EMAIL, name: "Portal Person" } }); + await prisma.asset.create({ data: { tenantId: tenant.id, name: "Asset der Person", type: "SYSTEM", ownerId: user.id, createdBy: user.id } }); + + // ── (4a) DSGVO-Paket (Per-Person) direkt ──────────────────────────────────── + console.log("\n(4) DSGVO-Zustellpaket:"); + const pkg = await buildDsgvoPackage(tenant.id, identity.id); + ok(pkg.summary.scope === "person", "Scope=person erkannt"); + const pdir = mkdtempSync(join(tmpdir(), "cvdsgvo-")); + const ppath = join(pdir, "p.zip"); + writeFileSync(ppath, pkg.zip); + let names = ""; + let identityJson = ""; + try { + names = execFileSync("unzip", ["-l", ppath], { encoding: "utf8" }); + identityJson = execFileSync("unzip", ["-p", ppath, "identity.json"], { encoding: "utf8" }); + } catch { /* ohne unzip überspringen */ } + ok(names.includes("identity.json") && names.includes("memberships.json") && names.includes("references.json"), "Paket enthält identity/memberships/references"); + ok(identityJson.includes(EMAIL), "identity.json enthält die E-Mail der Person"); + ok(!identityJson.includes("passwordHash") && !identityJson.includes("mfaSecret"), "identity.json enthält KEINE Secrets"); + rmSync(pdir, { recursive: true, force: true }); + + // ── (4b) dsgvo_export-Job (processBackupJob, ohne Redis) → Store + Token/TTL ─ + const job = await prisma.backupJob.create({ + data: { kind: "dsgvo_export", status: "queued", tenantId: tenant.id, tenantSlug: tenant.slug, subjectIdentityId: identity.id, actorId: null }, + }); + await processBackupJob({ kind: "dsgvo_export", jobId: job.id, tenantId: tenant.id, subjectIdentityId: identity.id, actorId: "test-admin" }); + const done = await prisma.backupJob.findUnique({ where: { id: job.id } }); + ok(done?.status === "done", "dsgvo_export-Job auf 'done' gesetzt"); + ok(!!done?.downloadToken && done.downloadToken.length >= 20, "signierter Download-Token erzeugt"); + ok(!!done?.downloadExpiresAt && done.downloadExpiresAt.getTime() > Date.now(), "TTL/Ablaufzeitpunkt in der Zukunft"); + const stored = await (await getBackupStore()).get(dsgvoPackageKey(tenant.id, job.id)); + ok(!!stored && stored.length > 0, "ZIP im Backup-Store abgelegt (für den Download-Endpunkt)"); +} + +main() + .then(async () => { + await cleanup(); + await prisma.$disconnect(); + if (failures > 0) { console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); process.exit(1); } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-backup-target.ts b/scripts/test-backup-target.ts new file mode 100644 index 0000000..ad74cc8 --- /dev/null +++ b/scripts/test-backup-target.ts @@ -0,0 +1,168 @@ +// Lane „Konfigurierbarer Backup-Zielspeicher": Store-Auflösung + Präzedenz + fail-secure. +// +// Deckt OHNE DB/Redis ab (reine Auflösungslogik `resolveBackupStore` + echte +// Byte-Persistenz des LocalBackupStore): +// (1) DB-Config lokal (expliziter Pfad) → LocalBackupStore auf genau diesem Pfad. +// (2) DB-Config S3 (vollständig) → S3BackupStore (kein still-lokaler Fallback). +// (3) Fail-secure: DB-Config S3 unvollständig → klarer Fehler (kein Local-Fallback). +// (4) Präzedenz DB → Env → Default (inkl. „unberührter Default-Datensatz fällt auf Env"). +// (5) „Verbindung testen"-Pfad: put→get→remove eines winzigen Test-Keys (Local, echt). +// +// Lauf: npx tsx scripts/test-backup-target.ts (braucht KEINE DB und KEIN Redis) + +import "dotenv/config"; +import { mkdtempSync, rmSync, existsSync, readFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { resolveBackupStore, type BackupTargetConfig } from "../src/server/storage/backup-store"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +/** Minimal-Config-Fabrik (nur die relevanten Felder überschreiben). */ +function cfg(partial: Partial): BackupTargetConfig { + return { + backupTarget: "local", + backupLocalDir: null, + backupS3Endpoint: null, + backupS3Bucket: null, + backupS3Region: null, + backupS3AccessKey: null, + backupS3SecretKey: null, + ...partial, + }; +} + +const storeKind = (s: unknown) => (s as { constructor: { name: string } }).constructor.name; + +/** Env-Variablen für einen Testblock setzen/entfernen und danach wiederherstellen. */ +function withEnv(vars: Record, fn: () => void) { + const S3_KEYS = ["S3_ENDPOINT", "S3_ACCESS_KEY", "S3_SECRET_KEY", "S3_BUCKET", "S3_REGION", "BACKUP_LOCAL_DIR"]; + const saved: Record = {}; + for (const k of S3_KEYS) saved[k] = process.env[k]; + try { + // Erst alle relevanten Keys leeren, dann die gewünschten setzen (deterministisch). + for (const k of S3_KEYS) delete process.env[k]; + for (const [k, v] of Object.entries(vars)) if (v !== undefined) process.env[k] = v; + fn(); + } finally { + for (const k of S3_KEYS) { + if (saved[k] === undefined) delete process.env[k]; + else process.env[k] = saved[k]; + } + } +} + +async function main() { + const tmp = mkdtempSync(join(tmpdir(), "cvbktarget-")); + + // ── (1) DB-Config lokal (expliziter Pfad) ────────────────────────────────── + console.log("\n(1) DB-Config lokal (expliziter Pfad):"); + const localDir = join(tmp, "db-local"); + withEnv({}, () => { + const store = resolveBackupStore(cfg({ backupTarget: "local", backupLocalDir: localDir })); + ok(storeKind(store) === "LocalBackupStore", "explizite lokale DB-Config → LocalBackupStore"); + }); + { + // Byte-Persistenz auf genau diesem Pfad nachweisen. + const store = resolveBackupStore(cfg({ backupTarget: "local", backupLocalDir: localDir })); + await store.put("t/probe.txt", Buffer.from("hi", "utf8")); + ok(existsSync(join(localDir, "t/probe.txt")), "Bytes landen unter dem konfigurierten Pfad"); + ok(readFileSync(join(localDir, "t/probe.txt"), "utf8") === "hi", "Inhalt korrekt persistiert"); + } + + // ── (2) DB-Config S3 vollständig ──────────────────────────────────────────── + console.log("\n(2) DB-Config S3 (vollständig):"); + withEnv({}, () => { + const store = resolveBackupStore( + cfg({ + backupTarget: "s3", + backupS3Endpoint: "http://minio:9000", + backupS3Bucket: "certvia-backups", + backupS3AccessKey: "AK", + backupS3SecretKey: "SK", + }), + ); + ok(storeKind(store) === "S3BackupStore", "vollständige S3-DB-Config → S3BackupStore (kein Local-Fallback)"); + }); + + // ── (3) Fail-secure: S3 unvollständig ─────────────────────────────────────── + console.log("\n(3) Fail-secure (S3 unvollständig):"); + withEnv({ S3_ENDPOINT: "http://env-minio:9000", S3_ACCESS_KEY: "E", S3_SECRET_KEY: "E", S3_BUCKET: "env" }, () => { + let threw = false; + try { + resolveBackupStore(cfg({ backupTarget: "s3", backupS3Endpoint: "http://minio:9000", backupS3Bucket: "b" })); + } catch { + threw = true; + } + ok(threw, "S3-DB-Config ohne Secret/Access-Key wirft (fällt NICHT still auf lokal/Env)"); + }); + + // ── (4) Präzedenz DB → Env → Default ──────────────────────────────────────── + console.log("\n(4) Präzedenz DB → Env → Default:"); + // (4a) Keine DB-Config, aber Env-S3 vollständig → S3 (Rückwärtskompatibilität). + withEnv({ S3_ENDPOINT: "http://env-minio:9000", S3_ACCESS_KEY: "E", S3_SECRET_KEY: "E", S3_BUCKET: "env" }, () => { + ok(storeKind(resolveBackupStore(null)) === "S3BackupStore", "cfg=null + Env-S3 → S3 (Env-Fallback)"); + }); + // (4b) „Unberührter Default-Datensatz" (local/NULL) fällt ebenfalls auf Env zurück. + withEnv({ S3_ENDPOINT: "http://env-minio:9000", S3_ACCESS_KEY: "E", S3_SECRET_KEY: "E", S3_BUCKET: "env" }, () => { + const store = resolveBackupStore(cfg({ backupTarget: "local", backupLocalDir: null })); + ok(storeKind(store) === "S3BackupStore", "DB local/NULL (unkonfiguriert) → Env-S3 gewinnt (Rückwärtskompatibilität)"); + }); + // (4c) Keine DB-Config, kein Env-S3, aber BACKUP_LOCAL_DIR gesetzt → Local dort. + const envLocalDir = join(tmp, "env-local"); + withEnv({ BACKUP_LOCAL_DIR: envLocalDir }, async () => { + const store = resolveBackupStore(null); + ok(storeKind(store) === "LocalBackupStore", "cfg=null + kein Env-S3, aber BACKUP_LOCAL_DIR → Local"); + }); + { + const store = withEnvReturn({ BACKUP_LOCAL_DIR: envLocalDir }, () => resolveBackupStore(null)); + await store.put("p.txt", Buffer.from("x", "utf8")); + ok(existsSync(join(envLocalDir, "p.txt")), "Env-BACKUP_LOCAL_DIR steuert den Ablagepfad"); + } + // (4d) Nichts gesetzt → lokaler Default /.backups. + withEnv({}, () => { + const store = resolveBackupStore(null); + ok(storeKind(store) === "LocalBackupStore", "cfg=null + keinerlei Env → lokaler Default (.backups)"); + }); + + // ── (5) „Verbindung testen"-Pfad (put→get→remove) ─────────────────────────── + console.log("\n(5) „Verbindung testen\"-Pfad (Local, put→get→remove):"); + { + const store = resolveBackupStore(cfg({ backupTarget: "local", backupLocalDir: join(tmp, "conn") })); + const key = "__connectivity-test__/probe.txt"; + const payload = Buffer.from("certvia connectivity", "utf8"); + await store.put(key, payload); + const back = await store.get(key); + ok(!!back && back.equals(payload), "put→get liefert identische Bytes"); + await store.remove(key); + ok((await store.get(key)) === null, "remove entfernt den Test-Key wieder (kein Rückstand)"); + } + + rmSync(tmp, { recursive: true, force: true }); +} + +/** Wie withEnv, aber gibt den Rückgabewert der Funktion durch (für synchrone Fälle). */ +function withEnvReturn(vars: Record, fn: () => T): T { + let out!: T; + withEnv(vars, () => { + out = fn(); + }); + return out; +} + +main() + .then(() => { + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch((e) => { + console.error(e); + process.exit(1); + }); diff --git a/scripts/test-doc-control.ts b/scripts/test-doc-control.ts new file mode 100644 index 0000000..57be5df --- /dev/null +++ b/scripts/test-doc-control.ts @@ -0,0 +1,73 @@ +// AP5 — Dokumentenlenkung: Prüfzyklus/-termin, Neuversion + Historie, Lesebestätigung +// je Version. Prüft die reine Zyklus-Logik und die Daten-Invarianten (Wegwerf-Mandant). +// +// Lauf: npx tsx scripts/test-doc-control.ts + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { computeNextReview, isReviewDue, bumpMinorVersion } from "../src/lib/review-cycle"; + +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; +const SLUG = "ap5-test-doc"; + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG }, select: { id: true } }); + if (!t) return; + await prisma.policyAcknowledgement.deleteMany({ where: { tenantId: t.id } }); + await prisma.policyDocumentVersion.deleteMany({ where: { tenantId: t.id } }); + await prisma.policyDocument.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); +} + +async function main() { + await cleanup(); + + // ── Reine Zyklus-Logik ────────────────────────────────────────────────────── + const from = new Date("2026-01-15T00:00:00Z"); + const next = computeNextReview(from, "jährlich"); + ok(next?.getUTCFullYear() === 2027 && next?.getUTCMonth() === 0, "computeNextReview: jährlich → +12 Monate"); + ok(computeNextReview(from, null) === null, "kein Zyklus → kein Termin"); + ok(isReviewDue(new Date("2020-01-01")) === true && isReviewDue(new Date("2999-01-01")) === false, "isReviewDue erkennt Überfälligkeit"); + ok(bumpMinorVersion("1.0") === "1.1" && bumpMinorVersion("2.9") === "2.10" && bumpMinorVersion("3") === "3.1", "bumpMinorVersion korrekt"); + + // ── Daten-Invarianten ─────────────────────────────────────────────────────── + const tenant = await prisma.tenant.create({ data: { name: "AP5", slug: SLUG } }); + const t = tenant.id; + const doc = await prisma.policyDocument.create({ + data: { tenantId: t, code: "R08", type: "RICHTLINIE", title: "Zugriffskontrolle", version: "1.0", rawMarkdown: "# Zugriffskontrolle" }, + select: { id: true, version: true }, + }); + + // Lesebestätigung v1.0 durch zwei Nutzer; Duplikat (gleicher Nutzer/Version) wird verhindert. + await prisma.policyAcknowledgement.create({ data: { tenantId: t, policyDocumentId: doc.id, userId: "user-1", version: "1.0" } }); + await prisma.policyAcknowledgement.create({ data: { tenantId: t, policyDocumentId: doc.id, userId: "user-2", version: "1.0" } }); + let dupBlocked = false; + try { + await prisma.policyAcknowledgement.create({ data: { tenantId: t, policyDocumentId: doc.id, userId: "user-1", version: "1.0" } }); + } catch { dupBlocked = true; } + ok(dupBlocked, "Lesebestätigung je (Dokument, Nutzer, Version) nur einmal (Unique)"); + ok((await prisma.policyAcknowledgement.count({ where: { policyDocumentId: doc.id, version: "1.0" } })) === 2, "2 Lesebestätigungen für v1.0"); + + // „Als geprüft markieren": Momentaufnahme + Minor-Bump. + await prisma.policyDocumentVersion.create({ data: { tenantId: t, policyDocumentId: doc.id, version: "1.0", title: "Zugriffskontrolle", changeNote: "Turnusmäßige Überprüfung", createdBy: "user-1" } }); + const newVersion = bumpMinorVersion(doc.version); + await prisma.policyDocument.update({ where: { id: doc.id }, data: { version: newVersion, reviewCycle: "jährlich", nextReviewAt: computeNextReview(new Date(), "jährlich") } }); + + const after = await prisma.policyDocument.findUnique({ where: { id: doc.id }, include: { versionHistory: true } }); + ok(after?.version === "1.1", "Neuversion nach Prüfung (v1.0 → v1.1)"); + ok((after?.versionHistory.length ?? 0) >= 1, "Versionshistorie enthält die frühere Version (≥2 Versionen sichtbar: Historie + aktuell)"); + + // Version-Scoping: alte Bestätigungen (v1.0) zählen NICHT für v1.1. + ok((await prisma.policyAcknowledgement.count({ where: { policyDocumentId: doc.id, version: "1.1" } })) === 0, "Lesebestätigungen sind versions-scoped (v1.1 startet bei 0)"); + + // Prüftermin gesetzt. + ok(after?.reviewCycle === "jährlich" && !!after?.nextReviewAt, "Prüfzyklus + nächster Prüftermin gesetzt"); + + await cleanup(); + console.log("\n✓ aufgeräumt (Wegwerf-Mandant entfernt)"); +} + +main() + .then(() => { console.log(failures === 0 ? "\nAP5-Dokumentenlenkung grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch(async (e) => { console.error(e); await cleanup().catch(() => {}); process.exit(1); }); diff --git a/scripts/test-framework-assessment.ts b/scripts/test-framework-assessment.ts new file mode 100644 index 0000000..dfa9b13 --- /dev/null +++ b/scripts/test-framework-assessment.ts @@ -0,0 +1,103 @@ +// B1 Schritt 1 — Snapshot-Regressionsnetz der heutigen TISAX-Bewertung. +// +// Hält die Ausgabe von buildControlRows (Reifegradvorschlag, Zielwert, Belegstatus und +// offene Punkte je Control) für den Demo-Mandanten als JSON im Repo fest. JEDE spätere +// Abweichung (ControlSpec-Umbau, Strategie-Extraktion) ist eine Regression, kein +// „ist besser geworden" (Feindesign §7, §7a: Schritt 1 ist die wichtigste Maßnahme). +// +// Baseline erzeugen/aktualisieren: UPDATE_SNAPSHOT=1 npx tsx scripts/test-framework-assessment.ts +// Prüfen (Merge-Gate): npx tsx scripts/test-framework-assessment.ts + +import "dotenv/config"; +import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { prisma, dbForTenant } from "../src/server/db"; +import { buildControlRows } from "../src/server/soa-context"; +import { buildAssessment } from "../src/server/assessment"; + +const SNAPSHOT = join(dirname(fileURLToPath(import.meta.url)), "snapshots", "framework-assessment-tisax.json"); + +/** Kanonisches JSON (rekursiv sortierte Objekt-Schlüssel) für stabilen Vergleich. */ +function canonical(v: unknown): unknown { + if (Array.isArray(v)) return v.map(canonical); + if (v && typeof v === "object") { + const out: Record = {}; + for (const k of Object.keys(v as Record).sort()) out[k] = canonical((v as Record)[k]); + return out; + } + return v; +} +const stable = (v: unknown) => JSON.stringify(canonical(v), null, 2); + +async function build() { + const tenant = await prisma.tenant.findFirst({ where: { slug: "demo" }, select: { id: true } }); + if (!tenant) throw new Error("Demo-Mandant fehlt (prisma/seed.ts ausführen)."); + const { rows, level } = await buildControlRows(dbForTenant(tenant.id), tenant.id); + // Nur die bewertungsrelevanten, deterministischen Felder je Control festhalten. + const controls = rows.map((r) => ({ + control: r.control, + target: r.target, + confirmed: r.confirmed, + suggestion: r.suggestion, + evidence: r.evidence, + gaps: r.gaps, + })); + return { level, count: controls.length, controls }; +} + +/** §7.2: buildAssessment("TISAX") auf dieselbe Snapshot-Form abbilden. */ +async function buildViaStrategy() { + const tenant = await prisma.tenant.findFirst({ where: { slug: "demo" }, select: { id: true } }); + const { rows } = await buildAssessment(dbForTenant(tenant!.id), tenant!.id, "TISAX"); + const controls = rows.map((r) => { + if (r.verdict.kind !== "maturity") throw new Error("TISAX-Verdict ist nicht 'maturity'."); + return { control: r.control, target: r.verdict.target, confirmed: r.verdict.confirmed, suggestion: r.verdict.suggestion, evidence: r.evidence, gaps: r.gaps }; + }); + return { level: "AL2", count: controls.length, controls }; +} + +async function main() { + const current = await build(); + + // Strategie-Äquivalenz (Feindesign §7.2): buildAssessment("TISAX") == buildControlRows. + const viaStrategy = await buildViaStrategy(); + if (stable(viaStrategy.controls) !== stable(current.controls)) { + console.error("✗ buildAssessment(\"TISAX\") weicht von buildControlRows ab — die Strategie-Schicht verändert TISAX."); + process.exit(1); + } + + if (process.env.UPDATE_SNAPSHOT === "1" || !existsSync(SNAPSHOT)) { + mkdirSync(dirname(SNAPSHOT), { recursive: true }); + writeFileSync(SNAPSHOT, stable(current) + "\n", "utf-8"); + console.log(`✓ Snapshot ${existsSync(SNAPSHOT) ? "aktualisiert" : "erstellt"}: ${current.count} Controls (Level ${current.level}).`); + console.log(" → Baseline committen; künftige Läufe prüfen gegen diesen Stand."); + return; + } + + const expected = readFileSync(SNAPSHOT, "utf-8").trim(); + const actual = stable(current).trim(); + if (expected === actual) { + console.log(`✓ TISAX-Snapshot unverändert: ${current.count} Controls, Level ${current.level} — 0 Abweichungen.`); + process.exit(0); + } + + // Erste abweichende Control-Zeile für die Diagnose zeigen. + const exp = JSON.parse(expected) as { controls: { control: string }[] }; + const expByControl = new Map(exp.controls.map((c) => [c.control, stable(c)])); + const diffs: string[] = []; + for (const c of current.controls) { + const e = expByControl.get(c.control); + const a = stable(c); + if (e !== a) diffs.push(c.control); + } + const onlyExpected = exp.controls.map((c) => c.control).filter((id) => !current.controls.some((c) => c.control === id)); + console.error(`✗ TISAX-Snapshot weicht ab. Betroffene Controls (${diffs.length}): ${diffs.slice(0, 20).join(", ")}`); + if (onlyExpected.length) console.error(` Fehlend gegenüber Baseline: ${onlyExpected.join(", ")}`); + console.error(" → Wenn die Änderung beabsichtigt ist: UPDATE_SNAPSHOT=1 erneut ausführen. Sonst Regression."); + process.exit(1); +} + +main() + .catch((e) => { console.error(e); process.exit(1); }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/test-framework-core.ts b/scripts/test-framework-core.ts new file mode 100644 index 0000000..6619ba5 --- /dev/null +++ b/scripts/test-framework-core.ts @@ -0,0 +1,93 @@ +// AP1 — Framework-Dimension: Kern-Invarianten (docs/UEBERGABE-framework-iso27001.md §1). +// +// Prüft gegen die lokale DB (Demo-Mandant): +// 1. Backfill: jeder Mandant hat ≥1 TenantFramework; Bestands-Anforderungen sind TISAX; +// getTenantFrameworks(demo) beginnt mit TISAX; Fallback ["TISAX"] ohne Zeile. +// 2. Beide Mappings parsen: mapping.json (VDA ISA) und mapping-iso.json (ISO) — gemeinsamer +// Dokumentensatz, unterschiedliche Anforderungen. +// 3. Doppel-Framework-Reconcile: ISO-Import in einen TISAX-Mandanten legt die ISO- +// Anforderungen an und archiviert KEINE TISAX-Anforderung (Falle 1.1); Dokumente +// werden nicht dupliziert (reconcileShared). +// 4. Rück-Reconcile TISAX archiviert die ISO-Anforderungen NICHT. +// Räumt die ISO-Testdaten am Ende wieder ab. +// +// Lauf: npx tsx scripts/test-framework-core.ts + +import "dotenv/config"; +import { join } from "node:path"; +import { prisma } from "../src/server/db"; +import { parsePackageFiles, reconcilePackage } from "../prisma/import-policies"; +import { getTenantFrameworks, getTenantPrimaryFramework } from "../prisma/template-store"; + +const SEED_DIR = join(process.cwd(), "seed", "isms-vorlagenpaket-v2"); +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; + +const activeReqs = (tenantId: string, framework: "TISAX" | "ISO_27001") => + prisma.policyRequirement.count({ where: { tenantId, framework, archivedAt: null } }); +const archivedReqs = (tenantId: string, framework: "TISAX" | "ISO_27001") => + prisma.policyRequirement.count({ where: { tenantId, framework, archivedAt: { not: null } } }); + +async function main() { + const tenant = await prisma.tenant.findFirst({ where: { slug: "demo" } }); + if (!tenant) throw new Error("Demo-Mandant fehlt (prisma/seed.ts ausführen)."); + const t = tenant.id; + + // ── 1. Backfill / Framework-Zuordnung ─────────────────────────────────────── + const allTenants = await prisma.tenant.count(); + const tenantsWithFw = await prisma.tenantFramework.groupBy({ by: ["tenantId"] }); + ok(tenantsWithFw.length === allTenants, `jeder Mandant hat ≥1 TenantFramework (${tenantsWithFw.length}/${allTenants})`); + + const demoFw = await getTenantFrameworks(prisma, t); + ok(demoFw[0] === "TISAX", "getTenantFrameworks(demo) beginnt mit TISAX"); + ok((await getTenantPrimaryFramework(prisma, t)) === "TISAX", "Primär-Framework = TISAX"); + ok((await getTenantFrameworks(prisma, "does-not-exist"))[0] === "TISAX", "Fallback ohne Zeile → [\"TISAX\"]"); + + const isoBaseline = await prisma.policyRequirement.count({ where: { tenantId: t, framework: "ISO_27001" } }); + ok(isoBaseline === 0, "Demo-Mandant hat vor dem Test keine ISO-Anforderungen"); + + // ── 2. Beide Mappings parsen ──────────────────────────────────────────────── + const tisaxPkg = parsePackageFiles(SEED_DIR, "mapping.json"); + const isoPkg = parsePackageFiles(SEED_DIR, "mapping-iso.json"); + ok(tisaxPkg.requirements.length > 300, `mapping.json: ${tisaxPkg.requirements.length} Anforderungen (VDA ISA)`); + ok(isoPkg.requirements.length === 120, `mapping-iso.json: ${isoPkg.requirements.length} Anforderungen (erwartet 120)`); + ok(tisaxPkg.documents.length === isoPkg.documents.length, "gemeinsamer Dokumentensatz (gleiche Dokumentanzahl)"); + + // ── 3. Doppel-Framework: ISO in TISAX-Mandant ─────────────────────────────── + const tisaxActiveBefore = await activeReqs(t, "TISAX"); + const tisaxArchivedBefore = await archivedReqs(t, "TISAX"); + const docsBefore = await prisma.policyDocument.count({ where: { tenantId: t } }); + + const isoRun = await reconcilePackage(prisma, t, isoPkg, { framework: "ISO_27001", reconcileShared: false }); + ok(isoRun.report.requirements.added === isoPkg.requirements.length, + `ISO-Import legt ${isoRun.report.requirements.added} Anforderungen an (= ${isoPkg.requirements.length})`); + ok(isoRun.report.documents.added === 0 && isoRun.report.documents.updated === 0, + "ISO-Import fasst die geteilten Dokumente NICHT an (reconcileShared=false)"); + + const isoActive = await activeReqs(t, "ISO_27001"); + ok(isoActive === isoPkg.requirements.length, `ISO-Anforderungen aktiv: ${isoActive}`); + + const tisaxActiveAfter = await activeReqs(t, "TISAX"); + const tisaxArchivedAfter = await archivedReqs(t, "TISAX"); + ok(tisaxActiveAfter === tisaxActiveBefore, `KEINE TISAX-Anforderung archiviert (aktiv ${tisaxActiveBefore} → ${tisaxActiveAfter})`); + ok(tisaxArchivedAfter === tisaxArchivedBefore, "ISO-Import erzeugt keine neu archivierten TISAX-Anforderungen (Falle 1.1)"); + + const docsAfter = await prisma.policyDocument.count({ where: { tenantId: t } }); + ok(docsAfter === docsBefore, `Dokumente nicht dupliziert (${docsBefore} → ${docsAfter})`); + + const coexist = tisaxActiveAfter + isoActive; + ok(tisaxActiveAfter > 0 && isoActive === 120, `Doppel-Framework: ${tisaxActiveAfter} TISAX + ${isoActive} ISO koexistieren (${coexist})`); + + // ── 4. Rück-Reconcile TISAX archiviert ISO NICHT ──────────────────────────── + await reconcilePackage(prisma, t, tisaxPkg, { framework: "TISAX", reconcileShared: true }); + const isoStillActive = await activeReqs(t, "ISO_27001"); + ok(isoStillActive === isoPkg.requirements.length, "TISAX-Re-Import archiviert die ISO-Anforderungen NICHT"); + + // ── Aufräumen: ISO-Testdaten entfernen (Demo-Mandant zurücksetzen) ────────── + const removed = await prisma.policyRequirement.deleteMany({ where: { tenantId: t, framework: "ISO_27001" } }); + console.log(`\n✓ aufgeräumt (${removed.count} ISO-Test-Anforderungen entfernt)`); +} + +main() + .then(() => { console.log(failures === 0 ? "\nAP1-Framework-Kern grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch((e) => { console.error(e); process.exit(1); }); diff --git a/scripts/test-framework-dryrun.ts b/scripts/test-framework-dryrun.ts new file mode 100644 index 0000000..cdb985c --- /dev/null +++ b/scripts/test-framework-dryrun.ts @@ -0,0 +1,118 @@ +// Abnahmetest der Mehr-Framework-Fähigkeit (ISO 27001 neben TISAX) — reiner Trockenlauf. +// +// Prüft die Zusagen aus docs/UEBERGABE-framework-iso27001.md, ohne etwas zu schreiben: +// 1. Paketebene: beide Mappings lesen denselben Dokumentensatz; kein ISO-Umsetzungstext +// ist leer; die Anforderungs-IDs beider Frameworks überschneiden sich nicht. +// 2. Falle 1.1: Ein ISO-Import in einen Mandanten mit TISAX archiviert KEINE +// TISAX-Anforderung (`report.requirements.archived === 0`). +// 3. Geteilte Inhalte (Dokumente, Variablen, Baseline, Nachweisregister) werden bei einem +// Mandanten, der das Paket bereits hat, nicht doppelt angelegt. +// 4. Der Trockenlauf hinterlässt keine Spuren: Zählstände vor und nach dem Lauf identisch. +// +// Lauf: npx tsx scripts/test-framework-dryrun.ts +// Nutzt die lokale Postgres-DB; .env liegt im Worktree. Ohne Mandanten läuft nur Teil 1. + +import "dotenv/config"; +import { join } from "node:path"; +import { prisma } from "../src/server/db"; +import { parsePackageFiles, reconcilePackage } from "../prisma/import-policies"; + +const SEED = join(process.cwd(), "seed", "isms-vorlagenpaket-v2"); +let failed = 0; + +function check(ok: boolean, label: string, detail = "") { + if (!ok) failed++; + console.log(` ${ok ? "✓" : "✗"} ${label}${detail ? " — " + detail : ""}`); +} + +async function counts(tenantId: string) { + return { + tisax: await prisma.policyRequirement.count({ where: { tenantId, framework: "TISAX", archivedAt: null } }), + tisaxArch: await prisma.policyRequirement.count({ where: { tenantId, framework: "TISAX", archivedAt: { not: null } } }), + iso: await prisma.policyRequirement.count({ where: { tenantId, framework: "ISO_27001", archivedAt: null } }), + docs: await prisma.policyDocument.count({ where: { tenantId, archivedAt: null } }), + }; +} + +async function main() { + console.log("1. Paketebene"); + const iso = parsePackageFiles(SEED, "mapping-iso.json"); + const tis = parsePackageFiles(SEED, "mapping.json"); + const isoCodes = iso.documents.map((d) => d.code).sort(); + const tisCodes = tis.documents.map((d) => d.code).sort(); + + check(JSON.stringify(isoCodes) === JSON.stringify(tisCodes), + "beide Mappings lesen denselben Dokumentensatz", `${isoCodes.length} Dokumente`); + check(iso.requirements.length === 120, + "ISO-Mapping enthält 120 Anforderungen", `${iso.requirements.length}`); + check(iso.requirements.filter((r) => !r.implementation.trim()).length === 0, + "kein ISO-Umsetzungstext ist leer"); + check(iso.requirements.every((r) => !!r.control), + "jede ISO-Anforderung trägt eine Control-Referenz"); + const overlap = iso.requirements.map((r) => r.reqId).filter((id) => tis.requirements.some((t) => t.reqId === id)); + check(overlap.length === 0, "Anforderungs-IDs beider Frameworks überschneiden sich nicht", + overlap.length ? overlap.slice(0, 3).join(", ") : ""); + + // Englische Fassung: gleiche Struktur, übersetzte Texte. + const SEED_EN = join(process.cwd(), "seed", "isms-vorlagenpaket-v2-en"); + const isoEn = parsePackageFiles(SEED_EN, "mapping-iso.json"); + check(isoEn.requirements.length === iso.requirements.length, + "EN-Fassung enthält gleich viele ISO-Anforderungen", `${isoEn.requirements.length}`); + check(JSON.stringify(isoEn.requirements.map((r) => r.reqId).sort()) + === JSON.stringify(iso.requirements.map((r) => r.reqId).sort()), + "EN- und DE-Fassung haben identische Anforderungs-IDs"); + check(isoEn.requirements.filter((r) => !r.implementation.trim()).length === 0, + "kein EN-Umsetzungstext ist leer"); + check(isoEn.documents.length === iso.documents.length, + "EN-Fassung hat denselben Dokumentenumfang", `${isoEn.documents.length}`); + + const tenants = await prisma.tenant.findMany({ select: { id: true, name: true, slug: true } }); + if (!tenants.length) { + console.log("\n(keine Mandanten in der DB — Teil 2 übersprungen)"); + return; + } + + for (const t of tenants) { + console.log(`\n2. Trockenlauf ISO_27001 gegen „${t.name}" (${t.slug})`); + const before = await counts(t.id); + console.log(` vorher: TISAX=${before.tisax} (archiviert ${before.tisaxArch}) · ISO=${before.iso} · Dokumente=${before.docs}`); + + const { report } = await reconcilePackage(prisma, t.id, iso, { dryRun: true, framework: "ISO_27001" }); + const r = report.requirements, d = report.documents; + console.log(` Anforderungen: +${r.added} ~${r.updated} =${r.unchanged} archiviert=${r.archived}`); + console.log(` Dokumente: +${d.added} ~${d.updated} =${d.unchanged} reaktiviert=${d.reactivated} archiviert=${d.archived}`); + + check(r.archived === 0, "Falle 1.1 — keine fremde Anforderung archiviert", `archived=${r.archived}`); + check(r.added + r.unchanged + r.updated === 120, "alle 120 ISO-Anforderungen erfasst"); + check(d.archived === 0, "kein geteiltes Dokument wird stillgelegt", `archived=${d.archived}`); + check(report.variables.obsolete === 0 && report.baseline.obsolete === 0 && report.evidence.obsolete === 0, + "geteilte Inhalte verlieren nichts (Variablen, Baseline, Nachweisregister)"); + // Mandant hat das Paket bereits: jedes vorhandene Paket-Dokument muss wiedererkannt + // werden; angelegt wird nur, was im Mandanten wirklich fehlt. + const vorhanden = await prisma.policyDocument.findMany({ + where: { tenantId: t.id, code: { in: iso.documents.map((x) => x.code) } }, + select: { code: true }, + }); + // Ein vorhandenes Dokument zählt je nach Zustand als unchanged, updated ODER + // reactivated (wenn es beim Mandanten stillgelegt war) — alle drei sind „wiedererkannt". + const wiedererkannt = d.unchanged + d.updated + d.reactivated; + check(wiedererkannt === vorhanden.length, + "jedes vorhandene Paket-Dokument wird wiedererkannt", + `vorhanden=${vorhanden.length} unchanged=${d.unchanged} updated=${d.updated} reaktiviert=${d.reactivated}`); + check(d.added === iso.documents.length - vorhanden.length, + "angelegt wird nur, was im Mandanten fehlt", + `added=${d.added} erwartet=${iso.documents.length - vorhanden.length}`); + + const after = await counts(t.id); + check(JSON.stringify(before) === JSON.stringify(after), + "Trockenlauf hat nichts geschrieben", JSON.stringify(after)); + } +} + +main() + .catch((e) => { console.error(e); failed++; }) + .finally(async () => { + await prisma.$disconnect(); + console.log(`\n${failed === 0 ? "OK — alle Prüfungen bestanden" : `FEHLGESCHLAGEN — ${failed} Prüfung(en)`}`); + process.exit(failed === 0 ? 0 : 1); + }); diff --git a/scripts/test-framework-provision.ts b/scripts/test-framework-provision.ts new file mode 100644 index 0000000..6853830 --- /dev/null +++ b/scripts/test-framework-provision.ts @@ -0,0 +1,106 @@ +// AP2 — Provisionierung & Sichtbarkeits-Flags (docs/UEBERGABE-framework-iso27001.md §2). +// +// Provisioniert je einen Mandanten als reines TISAX, reines ISO und Doppel-Framework +// und prüft: +// - TenantFramework-Zeilen (Primär zuerst), +// - Import je Framework (Anforderungszahlen, keine Cross-Archivierung, Dokumente +// nicht dupliziert), +// - FLAG_FW_TISAX / FLAG_FW_ISO27001 NACH dem Import korrekt gesetzt, +// - AL-/Schutzbedarf-Flags nur bei TISAX (reiner ISO-Mandant: nicht gesetzt). +// Räumt die Test-Mandanten (inkl. Identitäten) vor und nach dem Lauf ab. +// +// Lauf: npx tsx scripts/test-framework-provision.ts + +import "dotenv/config"; +import { join } from "node:path"; +import { prisma } from "../src/server/db"; +import { provisionTenant } from "../src/server/provision"; + +const SEED_DIR = join(process.cwd(), "seed", "isms-vorlagenpaket-v2"); +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; + +const T = { + tisax: { slug: "ap2-test-tisax", email: "admin@ap2-test-tisax.example" }, + iso: { slug: "ap2-test-iso", email: "admin@ap2-test-iso.example" }, + dual: { slug: "ap2-test-dual", email: "admin@ap2-test-dual.example" }, +}; +const SLUGS = Object.values(T).map((t) => t.slug); +const EMAILS = Object.values(T).map((t) => t.email); + +async function cleanup() { + const tenants = await prisma.tenant.findMany({ where: { slug: { in: SLUGS } }, select: { id: true } }); + const ids = tenants.map((t) => t.id); + if (ids.length) { + // FK-sichere Reihenfolge: Verknüpfungen → Kinder → Stamm. + await prisma.userRole.deleteMany({ where: { user: { tenantId: { in: ids } } } }); + await prisma.rolePermission.deleteMany({ where: { role: { tenantId: { in: ids } } } }); + await prisma.user.deleteMany({ where: { tenantId: { in: ids } } }); + await prisma.role.deleteMany({ where: { tenantId: { in: ids } } }); + for (const model of [ + "policyRequirement", "policyVariable", "policyDocument", "policyBaselineParam", + "policyEvidence", "policyPackageState", "tenantFramework", "tenantModule", + "managedRegister", "auditLog", + ] as const) { + // @ts-expect-error dynamischer Modellzugriff (alle tragen tenantId) + await prisma[model].deleteMany({ where: { tenantId: { in: ids } } }); + } + await prisma.tenantSettings.deleteMany({ where: { tenantId: { in: ids } } }); + await prisma.tenant.deleteMany({ where: { id: { in: ids } } }); + } + await prisma.identity.deleteMany({ where: { email: { in: EMAILS } } }); +} + +const flag = async (tenantId: string, key: string) => + (await prisma.policyVariable.findFirst({ where: { tenantId, key }, select: { value: true } }))?.value ?? null; +const reqCount = (tenantId: string, framework: "TISAX" | "ISO_27001") => + prisma.policyRequirement.count({ where: { tenantId, framework, archivedAt: null } }); + +async function provision(slug: string, email: string, frameworks: ("TISAX" | "ISO_27001")[]) { + return provisionTenant(prisma, { + name: slug, slug, admin: { email, name: "AP2 Test", password: "Str0ng-Passw0rt!" }, + frameworks, seedPoliciesDir: SEED_DIR, actorId: null, + }); +} + +async function main() { + await cleanup(); + + // ── Reines TISAX ──────────────────────────────────────────────────────────── + const tisax = await provision(T.tisax.slug, T.tisax.email, ["TISAX"]); + const tisaxFw = await prisma.tenantFramework.findMany({ where: { tenantId: tisax.id }, select: { framework: true, isPrimary: true } }); + ok(tisaxFw.length === 1 && tisaxFw[0].framework === "TISAX" && tisaxFw[0].isPrimary, "TISAX-Mandant: genau eine TenantFramework-Zeile (TISAX, primär)"); + ok((await reqCount(tisax.id, "TISAX")) === 321 && (await reqCount(tisax.id, "ISO_27001")) === 0, "TISAX-Mandant: 321 TISAX-, 0 ISO-Anforderungen"); + ok((await flag(tisax.id, "FLAG_FW_TISAX")) === "true" && (await flag(tisax.id, "FLAG_FW_ISO27001")) === "false", "TISAX-Mandant: FLAG_FW_TISAX=true, FLAG_FW_ISO27001=false"); + ok((await flag(tisax.id, "FLAG_HIGH_PROTECTION")) === "true", "TISAX-Mandant: AL-Flag FLAG_HIGH_PROTECTION gesetzt"); + + // ── Reines ISO ────────────────────────────────────────────────────────────── + const iso = await provision(T.iso.slug, T.iso.email, ["ISO_27001"]); + const isoFw = await prisma.tenantFramework.findMany({ where: { tenantId: iso.id }, select: { framework: true, isPrimary: true } }); + ok(isoFw.length === 1 && isoFw[0].framework === "ISO_27001" && isoFw[0].isPrimary, "ISO-Mandant: genau eine TenantFramework-Zeile (ISO, primär)"); + ok((await reqCount(iso.id, "ISO_27001")) === 120 && (await reqCount(iso.id, "TISAX")) === 0, "ISO-Mandant: 120 ISO-, 0 TISAX-Anforderungen"); + ok((await flag(iso.id, "FLAG_FW_ISO27001")) === "true" && (await flag(iso.id, "FLAG_FW_TISAX")) === "false", "ISO-Mandant: FLAG_FW_ISO27001=true, FLAG_FW_TISAX=false"); + ok((await flag(iso.id, "FLAG_HIGH_PROTECTION")) === "false", "ISO-Mandant: KEIN AL-Flag gesetzt (Default false, Übergabe §1.3)"); + const isoDocs = await prisma.policyDocument.count({ where: { tenantId: iso.id } }); + const isoDocCodes = (await prisma.policyDocument.findMany({ where: { tenantId: iso.id }, select: { code: true } })).map((d) => d.code); + ok(isoDocs === new Set(isoDocCodes).size, "ISO-Mandant: Dokumente nicht dupliziert (eindeutige Codes)"); + + // ── Doppel-Framework ───────────────────────────────────────────────────────── + const dual = await provision(T.dual.slug, T.dual.email, ["TISAX", "ISO_27001"]); + const dualFw = await prisma.tenantFramework.findMany({ where: { tenantId: dual.id }, orderBy: { isPrimary: "desc" }, select: { framework: true, isPrimary: true } }); + ok(dualFw.length === 2 && dualFw[0].framework === "TISAX" && dualFw[0].isPrimary && !dualFw[1].isPrimary, "Doppel-Mandant: zwei Zeilen, TISAX primär"); + const dTisax = await reqCount(dual.id, "TISAX"); + const dIso = await reqCount(dual.id, "ISO_27001"); + ok(dTisax === 321 && dIso === 120, `Doppel-Mandant: 321 TISAX + 120 ISO koexistieren (${dTisax}+${dIso})`); + ok((await flag(dual.id, "FLAG_FW_TISAX")) === "true" && (await flag(dual.id, "FLAG_FW_ISO27001")) === "true", "Doppel-Mandant: beide FLAG_FW_* = true"); + const dualDocs = await prisma.policyDocument.count({ where: { tenantId: dual.id } }); + const dualCodes = (await prisma.policyDocument.findMany({ where: { tenantId: dual.id }, select: { code: true } })).map((d) => d.code); + ok(dualDocs === new Set(dualCodes).size, `Doppel-Mandant: Dokumente NICHT dupliziert (${dualDocs} eindeutige Codes)`); + + await cleanup(); + console.log("\n✓ aufgeräumt (Test-Mandanten + Identitäten entfernt)"); +} + +main() + .then(() => { console.log(failures === 0 ? "\nAP2-Provisionierung grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch(async (e) => { console.error(e); await cleanup().catch(() => {}); process.exit(1); }); diff --git a/scripts/test-framework-templates.ts b/scripts/test-framework-templates.ts new file mode 100644 index 0000000..8fb9d88 --- /dev/null +++ b/scripts/test-framework-templates.ts @@ -0,0 +1,62 @@ +// Vorlagen-Versionierung je Framework (Falle 1.2, docs/UEBERGABE-framework-iso27001.md §1). +// +// Sichert die Daten-Invariante, auf der der framework-fähige Vorlagen-Editor +// (policy-templates.ts) aufsetzt — ohne die session-geschützten Actions aufzurufen: +// 1. Dieselbe Versionsnummer darf je Framework existieren (@@unique([framework, version])): +// (TISAX, "99.1") UND (ISO_27001, "99.1") koexistieren. +// 2. Das Publish-Archivieren ist framework-scoped: ein `updateMany` mit +// `framework=ISO_27001` archiviert NUR die ISO-Version, die TISAX-Version bleibt +// PUBLISHED (sonst archivierte ein ISO-Publish die TISAX-Vorlage und umgekehrt). +// Nutzt eindeutige Wegwerf-Versionen ("99.1") und räumt sie wieder ab. +// +// Lauf: npx tsx scripts/test-framework-templates.ts + +import "dotenv/config"; +import { prisma } from "../src/server/db"; + +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; +const V = "99.1"; // Wegwerf-Version, kollidiert nicht mit echten Paketständen + +async function cleanup() { + await prisma.policyTemplateVersion.deleteMany({ where: { version: V } }); +} + +async function main() { + await cleanup(); + + // ── 1. Gleiche Version je Framework koexistiert (Unique-Constraint) ────────── + const tisax = await prisma.policyTemplateVersion.create({ data: { framework: "TISAX", version: V, status: "PUBLISHED", publishedAt: new Date() } }); + let isoCreated = false; + try { + await prisma.policyTemplateVersion.create({ data: { framework: "ISO_27001", version: V, status: "PUBLISHED", publishedAt: new Date() } }); + isoCreated = true; + } catch { + isoCreated = false; + } + ok(isoCreated, "gleiche Versionsnummer je Framework erlaubt (@@unique([framework, version]))"); + + const both = await prisma.policyTemplateVersion.findMany({ where: { version: V }, select: { framework: true } }); + ok(both.length === 2, "beide Versionen (TISAX + ISO) existieren nebeneinander"); + + // ── 2. Framework-scopes Archivieren (wie publishDraft) ────────────────────── + const ids = (await prisma.policyTemplateVersion.findMany({ where: { version: V }, select: { id: true } })).map((r) => r.id); + // Repliziert die Publish-Bedingung `where { status: PUBLISHED, framework }` — zusätzlich + // auf die Testzeilen eingegrenzt, um echte Paketstände nicht anzufassen. + await prisma.policyTemplateVersion.updateMany({ + where: { status: "PUBLISHED", framework: "ISO_27001", id: { in: ids } }, + data: { status: "ARCHIVED" }, + }); + const tisaxAfter = await prisma.policyTemplateVersion.findFirst({ where: { framework: "TISAX", version: V }, select: { status: true } }); + const isoAfter = await prisma.policyTemplateVersion.findFirst({ where: { framework: "ISO_27001", version: V }, select: { status: true } }); + ok(tisaxAfter?.status === "PUBLISHED", "TISAX-Version bleibt PUBLISHED, wenn ISO archiviert wird"); + ok(isoAfter?.status === "ARCHIVED", "ISO-Version wird archiviert (framework-scoped)"); + + void tisax; + await cleanup(); + console.log("\n✓ aufgeräumt (Wegwerf-Versionen entfernt)"); +} + +main() + .then(() => { console.log(failures === 0 ? "\nVorlagen-Versionierung je Framework grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch(async (e) => { console.error(e); await cleanup().catch(() => {}); process.exit(1); }); diff --git a/scripts/test-framework-toggle.ts b/scripts/test-framework-toggle.ts new file mode 100644 index 0000000..9589026 --- /dev/null +++ b/scripts/test-framework-toggle.ts @@ -0,0 +1,150 @@ +// Test der nachträglichen Framework-Umschaltung (Admin: setTenantFrameworks). +// +// Spiegelt die Datenoperationen der Server-Action gegen die lokale DB und stellt den +// Ausgangszustand danach wieder her. Der Auth-Guard (`requirePlatformFullAdmin`) wird +// dabei NICHT durchlaufen — er ist identisch zu den sechs übrigen Admin-Aktionen. +// +// Geprüft wird: +// 1. Aktivieren — Framework-Zeile entsteht, 120 ISO-Anforderungen werden angelegt, +// die 321 TISAX-Anforderungen bleiben unangetastet, Flags stehen richtig. +// 2. Deaktivieren — Zugehörigkeit fällt weg, ISO-Anforderungen werden STILLGELEGT +// (archivedAt), nicht gelöscht; SoA-Einträge bleiben vollständig erhalten. +// 3. Wiederherstellung — der Mandant steht am Ende exakt wie vorher. +// +// Lauf: npx tsx scripts/test-framework-toggle.ts +// Nutzt die lokale Postgres-DB; .env liegt im Worktree. + +import "dotenv/config"; +import { join } from "node:path"; +import type { Framework } from "@prisma/client"; +import { prisma, dbForTenant } from "../src/server/db"; +import { reconcilePackage, stampPackageVersion } from "../prisma/import-policies"; +import { resolvePackageForTenant, getTenantFrameworks } from "../prisma/template-store"; + +const SEED = join(process.cwd(), "seed", "isms-vorlagenpaket-v2"); +let failed = 0; + +function check(ok: boolean, label: string, detail = "") { + if (!ok) failed++; + console.log(` ${ok ? "✓" : "✗"} ${label}${detail ? " — " + detail : ""}`); +} + +async function state(tenantId: string) { + const db = dbForTenant(tenantId); + const [fw, tisax, tisaxArch, iso, isoArch, soa, flags] = await Promise.all([ + getTenantFrameworks(prisma, tenantId), + db.policyRequirement.count({ where: { framework: "TISAX", archivedAt: null } }), + db.policyRequirement.count({ where: { framework: "TISAX", archivedAt: { not: null } } }), + db.policyRequirement.count({ where: { framework: "ISO_27001", archivedAt: null } }), + db.policyRequirement.count({ where: { framework: "ISO_27001", archivedAt: { not: null } } }), + db.soaEntry.count(), + db.policyVariable.findMany({ + where: { key: { in: ["FLAG_FW_TISAX", "FLAG_FW_ISO27001"] } }, + select: { key: true, value: true }, orderBy: { key: "asc" }, + }), + ]); + return { fw, tisax, tisaxArch, iso, isoArch, soa, flags: flags.map((f) => `${f.key}=${f.value}`).join(" ") }; +} + +/** Datenoperationen aus `setTenantFrameworks` (ohne Auth-Guard und revalidatePath). */ +async function apply(tenantId: string, wanted: Framework[]) { + const current = await getTenantFrameworks(prisma, tenantId); + const added = wanted.filter((f) => !current.includes(f)); + const removed = current.filter((f) => !wanted.includes(f)); + const db = dbForTenant(tenantId); + + for (const [i, framework] of wanted.entries()) { + await prisma.tenantFramework.upsert({ + where: { tenantId_framework: { tenantId, framework } }, + update: { isPrimary: i === 0 }, + create: { tenantId, framework, isPrimary: i === 0 }, + }); + } + for (const [i, framework] of added.entries()) { + const { pkg } = await resolvePackageForTenant(prisma, tenantId, SEED, framework); + await reconcilePackage(prisma, tenantId, pkg, { framework, reconcileShared: i === 0 }); + await stampPackageVersion(prisma, tenantId, pkg.version, framework); + } + if (removed.length > 0) { + await prisma.tenantFramework.deleteMany({ where: { tenantId, framework: { in: removed } } }); + await db.policyRequirement.updateMany({ + where: { framework: { in: removed }, archivedAt: null }, + data: { archivedAt: new Date() }, + }); + } + await db.policyVariable.updateMany({ where: { key: "FLAG_FW_TISAX" }, data: { value: String(wanted.includes("TISAX")) } }); + await db.policyVariable.updateMany({ where: { key: "FLAG_FW_ISO27001" }, data: { value: String(wanted.includes("ISO_27001")) } }); +} + +async function main() { + const tenant = await prisma.tenant.findFirst({ where: { slug: "demo" }, select: { id: true, name: true } }); + if (!tenant) { console.log("Mandant demo nicht gefunden — Test uebersprungen."); return; } + + const before = await state(tenant.id); + console.log(`Mandant: ${tenant.name}`); + console.log(` vorher: ${before.fw.join("+")} · TISAX=${before.tisax}/${before.tisaxArch} · ISO=${before.iso}/${before.isoArch} · SoA=${before.soa} · ${before.flags}`); + + try { + console.log("\n1. ISO aktivieren"); + await apply(tenant.id, [...before.fw, "ISO_27001"] as Framework[]); + const on = await state(tenant.id); + console.log(` ${on.fw.join("+")} · TISAX=${on.tisax}/${on.tisaxArch} · ISO=${on.iso}/${on.isoArch} · ${on.flags}`); + check(on.fw.includes("ISO_27001"), "Framework-Zugehörigkeit angelegt"); + check(on.iso === 120, "120 ISO-Anforderungen aktiv", `${on.iso}`); + check(on.tisax === before.tisax && on.tisaxArch === before.tisaxArch, + "TISAX-Anforderungen unangetastet", `${on.tisax} aktiv / ${on.tisaxArch} archiviert`); + check(on.flags.includes("FLAG_FW_ISO27001=true") && on.flags.includes("FLAG_FW_TISAX=true"), + "Sichtbarkeits-Flags gesetzt", on.flags); + + // Gepflegte SoA-Inhalte anlegen — sonst liefe die Erhaltungsprüfung unten über 0 → 0. + const db0 = dbForTenant(tenant.id); + for (const control of ["A.5.15", "A.8.5", "A.7.7"]) { + await db0.soaEntry.upsert({ + where: { tenantId_framework_control: { tenantId: tenant.id, framework: "ISO_27001", control } }, + update: { justification: "Testbegruendung", implementationStatus: "umgesetzt" }, + create: { + tenantId: tenant.id, framework: "ISO_27001", control, + justification: "Testbegruendung", implementationStatus: "umgesetzt", applicable: true, + }, + }); + } + const gepflegt = await db0.soaEntry.count({ where: { justification: "Testbegruendung" } }); + check(gepflegt === 3, "SoA-Einträge zum Test gepflegt", `${gepflegt}`); + + console.log("\n2. ISO wieder deaktivieren"); + await apply(tenant.id, before.fw as Framework[]); + const off = await state(tenant.id); + console.log(` ${off.fw.join("+")} · TISAX=${off.tisax}/${off.tisaxArch} · ISO=${off.iso}/${off.isoArch} · SoA=${off.soa} · ${off.flags}`); + check(!off.fw.includes("ISO_27001"), "Zugehörigkeit entfernt"); + check(off.iso === 0 && off.isoArch === 120, + "ISO-Anforderungen stillgelegt statt gelöscht", `aktiv=${off.iso} archiviert=${off.isoArch}`); + check(off.tisax === before.tisax, "TISAX weiterhin unangetastet", `${off.tisax}`); + const ueberlebt = await dbForTenant(tenant.id).soaEntry.count({ where: { justification: "Testbegruendung" } }); + check(ueberlebt === 3, "gepflegte SoA-Begründungen überleben das Deaktivieren unverändert", `${ueberlebt} von 3`); + check(off.flags.includes("FLAG_FW_ISO27001=false"), "Flag zurückgesetzt", off.flags); + + console.log("\n3. Erneut aktivieren — stillgelegte Anforderungen reaktivieren"); + await apply(tenant.id, [...before.fw, "ISO_27001"] as Framework[]); + const again = await state(tenant.id); + check(again.iso === 120 && again.isoArch === 0, + "Re-Import reaktiviert statt zu duplizieren", `aktiv=${again.iso} archiviert=${again.isoArch}`); + } finally { + console.log("\n4. Ausgangszustand wiederherstellen"); + await apply(tenant.id, before.fw as Framework[]); + const db = dbForTenant(tenant.id); + await db.policyRequirement.deleteMany({ where: { framework: "ISO_27001" } }); + await db.soaEntry.deleteMany({ where: { framework: "ISO_27001" } }); + const end = await state(tenant.id); + console.log(` ${end.fw.join("+")} · TISAX=${end.tisax}/${end.tisaxArch} · ISO=${end.iso}/${end.isoArch} · ${end.flags}`); + check(JSON.stringify(end) === JSON.stringify(before), "Mandant steht wie vorher", + JSON.stringify(end) === JSON.stringify(before) ? "" : `${JSON.stringify(before)} → ${JSON.stringify(end)}`); + } +} + +main() + .catch((e) => { console.error(e); failed++; }) + .finally(async () => { + await prisma.$disconnect(); + console.log(`\n${failed === 0 ? "OK — alle Prüfungen bestanden" : `FEHLGESCHLAGEN — ${failed} Prüfung(en)`}`); + process.exit(failed === 0 ? 0 : 1); + }); diff --git a/scripts/test-ft-rules.ts b/scripts/test-ft-rules.ts new file mode 100644 index 0000000..1d64754 --- /dev/null +++ b/scripts/test-ft-rules.ts @@ -0,0 +1,60 @@ +// Akzeptanztest der Funktionstrennungs-Regeln FT-01…FT-06 (Story A4-2, C7 §2). +// Reine Logik, kein DB-Zugriff. Lauf: npx tsx scripts/test-ft-rules.ts + +import { evaluateFt, type FtRoleInput } from "../src/lib/ft-rules"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const base: FtRoleInput = { + roles: { ISB: "Frau A", MANAGEMENT: "Herr B", IT_LEAD: "Herr C", HR_LEAD: "Frau D", DPO: "Herr E" }, + isbNamed: true, isbIsIt: false, isbInternal: false, personalData: false, +}; +const codes = (i: FtRoleInput) => evaluateFt(i).map((f) => f.code); +const byCode = (i: FtRoleInput, c: string) => evaluateFt(i).find((f) => f.code === c); + +// — Sauberer Fall: nur FT-06 (manueller Hinweis) — +ok(JSON.stringify(codes(base)) === JSON.stringify(["FT-06"]), "sauber → nur FT-06 (manuell)"); + +// — FT-04: ISB nicht benannt → Lücke + Aufgabe (reuse isb_not_named) — +{ + const f = byCode({ ...base, isbNamed: false }, "FT-04"); + ok(!!f && f.severity === "luecke" && f.task?.origin === "isb_not_named" && f.task?.reuse === true, "FT-04 ISB nicht benannt → Lücke + Aufgabe (reuse)"); +} + +// — FT-01: ISB = IT → Konflikt + Aufgabe (reuse isb_equals_it) — +{ + const f = byCode({ ...base, isbIsIt: true }, "FT-01"); + ok(!!f && f.severity === "konflikt" && f.task?.origin === "isb_equals_it" && f.task?.reuse === true, "FT-01 ISB=IT → Konflikt + Aufgabe (reuse)"); +} + +// — FT-03: ISB = Leitung → Konflikt + neue Aufgabe ft-03 — +{ + const f = byCode({ ...base, roles: { ...base.roles, MANAGEMENT: "Frau A" } }, "FT-03"); + ok(!!f && f.severity === "konflikt" && f.task?.origin === "ft-03" && f.task?.reuse === false, "FT-03 ISB=Leitung → Konflikt + neue Aufgabe"); +} + +// — FT-05: DPO fehlt trotz personenbezogener Daten → Lücke + neue Aufgabe ft-05 — +{ + const f = byCode({ ...base, personalData: true, roles: { ...base.roles, DPO: "" } }, "FT-05"); + ok(!!f && f.severity === "luecke" && f.task?.origin === "ft-05" && f.task?.reuse === false, "FT-05 DPO fehlt + FLAG_PERSONAL_DATA → Lücke + neue Aufgabe"); + // Kein FT-05, wenn DPO gesetzt: + ok(!byCode({ ...base, personalData: true }, "FT-05"), "FT-05 nicht, wenn DPO benannt"); + // Kein FT-05, wenn keine personenbezogenen Daten: + ok(!byCode({ ...base, roles: { ...base.roles, DPO: "" } }, "FT-05"), "FT-05 nicht ohne FLAG_PERSONAL_DATA"); +} + +// — FT-02: interner ISB (nicht IT) → schwacher Hinweis, keine Aufgabe — +{ + const f = byCode({ ...base, isbInternal: true }, "FT-02"); + ok(!!f && f.severity === "schwach" && !f.task, "FT-02 interner ISB → Hinweis ohne Aufgabe"); +} + +// — FT-06 immer vorhanden (manuell) — +ok(!!byCode(base, "FT-06") && !byCode(base, "FT-06")!.task, "FT-06 immer vorhanden, ohne Aufgabe"); + +console.log(failures === 0 ? "\nOK — alle FT-Tests grün" : `\nPRUEFEN — ${failures} Fehler`); +process.exit(failures === 0 ? 0 : 1); diff --git a/scripts/test-gap-consolidation.ts b/scripts/test-gap-consolidation.ts new file mode 100644 index 0000000..051f9af --- /dev/null +++ b/scripts/test-gap-consolidation.ts @@ -0,0 +1,91 @@ +// Unit-Tests (Story A8) für die Gap-Konsolidierung gegen die C8-Beispiele. +// Lauf: npx tsx scripts/test-gap-consolidation.ts +import { consolidate, gapPriority, isQuickWin, summarize, type RawGap } from "../src/lib/gap-consolidation"; + +let failed = 0; +function check(name: string, cond: boolean, detail = "") { + if (cond) console.log(` ok ${name}`); + else { + failed++; + console.error(`FAIL ${name}${detail ? ` — ${detail}` : ""}`); + } +} + +function raw(p: Partial): RawGap { + return { + id: p.id ?? "x", + source: p.source ?? "control", + title: p.title ?? "", + action: p.action ?? "", + controls: p.controls ?? [], + effort: p.effort ?? "mittel", + maturityImpact: p.maturityImpact ?? 1, + hasDependency: p.hasDependency ?? false, + taskOrigin: p.taskOrigin ?? "wizard:gap", + ...p, + }; +} + +// C8 §1 Prioritätsregeln + §4 Beispieltabelle. +console.log("§1/§4 Priorität:"); +check( + "Kein Patchmanagement (MUSS<2 + Risiko) → Hoch", + gapPriority(raw({ requirementType: "MUSS", maturity: 1, riskScore: 16, aboveAcceptance: true })) === "hoch", +); +check( + "Restore-Test fehlt (MUSS-Nachweis) → Hoch", + gapPriority(raw({ requirementType: "MUSS", maturity: 1, kind: "nachweis" })) === "hoch", +); +check("ISB=IT (FT-01 Konflikt) → Hoch", gapPriority(raw({ ftConflict: true, source: "role" })) === "hoch"); +check( + "SOLL Berechtigungs-Review nur Vorlage → Mittel", + gapPriority(raw({ requirementType: "SOLL", kind: "verfahren", maturity: 1 })) === "mittel", +); +check("Zonenbezeichnung redaktionell → Niedrig", gapPriority(raw({ kind: "redaktionell", maturity: 3 })) === "niedrig"); +check( + "MUSS-Control Reifegrad 2 unter Ziel 3 → Mittel", + gapPriority(raw({ requirementType: "MUSS", maturity: 2, target: 3, kind: "nachweis" })) === "mittel", +); +check("HOCH-Zusatzanforderung offen → Hoch", gapPriority(raw({ requirementType: "HOCH", maturity: 2, target: 3 })) === "hoch"); + +// C8 §3 Quick-Wins. +console.log("§3 Quick-Wins:"); +check("Restore-Test (organisatorisch, +1) → Quick-Win", isQuickWin(raw({ effort: "gering", maturityImpact: 1 }))); +check("Patchmanagement (Tool) → kein Quick-Win", !isQuickWin(raw({ effort: "hoch", maturityImpact: 1 }))); +check("Abhängigkeit → kein Quick-Win", !isQuickWin(raw({ effort: "gering", maturityImpact: 1, hasDependency: true }))); +check("keine Reifegrad-Wirkung → kein Quick-Win", !isQuickWin(raw({ effort: "gering", maturityImpact: 0 }))); + +// C8 §2 Deduplizierung. +console.log("§2 Deduplizierung:"); +const dupSame = consolidate([ + raw({ id: "control:5.2.3:nachweis", source: "control", controls: ["5.2.3"], kind: "nachweis", requirementType: "MUSS", maturity: 2, target: 3 }), + raw({ id: "control:5.2.3:nachweis", source: "control", controls: ["5.2.3"], kind: "nachweis", requirementType: "MUSS", maturity: 2, target: 3 }), +]); +check("gleiche Teilanforderung → ein Punkt", dupSame.length === 1); + +// Cross-Source-Merge: Risiko-Maßnahme + Control-Gaps derselben Controls (C8 §2, R-OPS-03-Beispiel). +const crossMerge = consolidate([ + raw({ id: "risk:R1", source: "risk", controls: ["5.2.3", "5.2.5"], riskScore: 16, aboveAcceptance: true, title: "Patchmanagement", taskId: "t1" }), + raw({ id: "control:5.2.3:nachweis", source: "control", controls: ["5.2.3"], kind: "nachweis", requirementType: "MUSS", maturity: 2, target: 3 }), + raw({ id: "control:5.2.5:nachweis", source: "control", controls: ["5.2.5"], kind: "nachweis", requirementType: "MUSS", maturity: 2, target: 3 }), + raw({ id: "control:1.1.1:nachweis", source: "control", controls: ["1.1.1"], kind: "nachweis", requirementType: "MUSS", maturity: 2, target: 3 }), +]); +check("Risiko absorbiert zugehörige Control-Gaps → 2 Punkte (Risiko + 1.1.1)", crossMerge.length === 2); +const riskItem = crossMerge.find((i) => i.source === "risk")!; +check("gemergter Risiko-Punkt hat Priorität Hoch", riskItem.priority === "hoch"); +check("gemergter Risiko-Punkt vereint 5.2.3/5.2.5", riskItem.controls.includes("5.2.3") && riskItem.controls.includes("5.2.5")); +check("gemergter Risiko-Punkt behält bestehende Aufgabe", riskItem.taskId === "t1"); +check("Risiko-Punkt vor Control-Punkt sortiert (Priorität + betroffene Controls)", crossMerge[0].source === "risk"); + +// Sortierung: Hoch vor Mittel. +console.log("Sortierung & Summary:"); +const sorted = consolidate([ + raw({ id: "a", source: "control", controls: ["3.1.1"], kind: "redaktionell", maturity: 3 }), + raw({ id: "b", source: "control", controls: ["1.4.1"], requirementType: "MUSS", maturity: 1, kind: "verfahren" }), +]); +check("Hoch (b) vor Niedrig (a)", sorted[0].id === "b" && sorted[1].id === "a"); +const sum = summarize(sorted); +check("Summary zählt korrekt", sum.total === 2 && sum.hoch === 1 && sum.niedrig === 1); + +console.log(failed === 0 ? "\nAlle Gap-Konsolidierungs-Tests grün." : `\n${failed} Test(s) fehlgeschlagen.`); +process.exit(failed === 0 ? 0 : 1); diff --git a/scripts/test-garage-storage.ts b/scripts/test-garage-storage.ts new file mode 100644 index 0000000..56a085d --- /dev/null +++ b/scripts/test-garage-storage.ts @@ -0,0 +1,99 @@ +// Smoke-Test des S3-Objektspeichers gegen einen echten Garage-Node (Phase C/D der +// MinIO→Garage-Migration, docs/KONZEPT-garage-migration.md §9). +// +// Prüft den realen S3-Pfad (AWS SDK v3, path-style) über die exportierte +// `resolveBackupStore()`: +// 1. Put → Get (Byte-Identität), +// 2. List (Prefix enthält den Key), +// 3. Delete (remove räumt den Prefix), +// 4. Negativfall: fehlender Bucket → sprechender Konfigurationsfehler +// (KEIN stiller CreateBucket-Versuch mehr). +// +// Ausführung: +// - OHNE S3_ENDPOINT → der Test ÜBERSPRINGT sich (Exit 0), damit das Standard-Gate +// (npm run test) ohne laufenden Objektspeicher grün bleibt. +// - MIT gesetzten S3_*-Variablen (z. B. gegen den Compose-Garage oder einen lokalen +// Container) → echter End-to-End-Durchstich. +// +// S3_ENDPOINT=http://127.0.0.1:3900 S3_ACCESS_KEY=… S3_SECRET_KEY=… \ +// S3_BUCKET=isms-documents S3_REGION=us-east-1 npx tsx scripts/test-garage-storage.ts + +import { resolveBackupStore, type BackupTargetConfig } from "../src/server/storage/backup-store"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +function envCfg(bucketOverride?: string): BackupTargetConfig { + return { + backupTarget: "s3", + backupLocalDir: null, + backupS3Endpoint: process.env.S3_ENDPOINT?.trim() ?? null, + backupS3Bucket: bucketOverride ?? process.env.S3_BUCKET?.trim() ?? "isms-documents", + backupS3Region: process.env.S3_REGION?.trim() || "us-east-1", + backupS3AccessKey: process.env.S3_ACCESS_KEY?.trim() ?? null, + backupS3SecretKey: process.env.S3_SECRET_KEY?.trim() ?? null, + }; +} + +async function main() { + const endpoint = process.env.S3_ENDPOINT?.trim(); + if (!endpoint) { + console.log("↷ übersprungen: kein S3_ENDPOINT gesetzt (kein laufender Objektspeicher)."); + console.log(" Für den echten Durchstich S3_ENDPOINT/S3_ACCESS_KEY/S3_SECRET_KEY/S3_BUCKET setzen."); + return; + } + if (!process.env.S3_ACCESS_KEY || !process.env.S3_SECRET_KEY) { + console.log("✗ FEHLER S3_ENDPOINT gesetzt, aber S3_ACCESS_KEY/S3_SECRET_KEY fehlen."); + failures++; + return; + } + + // ── Positiv: Put → Get → List → Delete gegen den provisionierten Bucket ────── + const store = resolveBackupStore(envCfg()); + const prefix = `__smoketest__/${process.pid}-${Date.now()}/`; + const key = `${prefix}garage-probe.bin`; + const payload = Buffer.from("certvia · garage smoke test · äöü · 🗄️", "utf8"); + + await store.put(key, payload); + ok(true, "Put gegen Garage erfolgreich"); + + const got = await store.get(key); + ok(got != null && got.equals(payload), "Get liefert identische Bytes zurück"); + + const missing = await store.get(`${prefix}gibtsnicht.bin`); + ok(missing === null, "Get eines fehlenden Keys → null (kein Wurf)"); + + const listed = await store.list(prefix); + ok(listed.includes(key), "List enthält den geschriebenen Key (Prefix-Scan)"); + + const removed = await store.remove(prefix); + ok(removed >= 1, `Delete räumt den Prefix (entfernt: ${removed})`); + const afterRemove = await store.list(prefix); + ok(afterRemove.length === 0, "Prefix ist nach remove leer"); + + // ── Negativ: fehlender Bucket → sprechender Konfigurationsfehler ───────────── + const badBucket = `does-not-exist-${process.pid}-${Date.now()}`; + const badStore = resolveBackupStore(envCfg(badBucket)); + try { + await badStore.put(`${badBucket}/x.bin`, Buffer.from("x")); + ok(false, "fehlender Bucket hätte einen Fehler werfen müssen"); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + const speaks = /nicht provisioniert|nicht erreichbar/.test(msg) && msg.includes(badBucket); + ok(speaks, "fehlender Bucket → sprechender Konfigurationsfehler (kein stiller CreateBucket)"); + if (!speaks) console.log(" erhaltene Meldung:", msg); + } +} + +main() + .then(() => { + console.log(failures === 0 ? "\nGarage-Storage-Smoke-Test grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(failures === 0 ? 0 : 1); + }) + .catch((err) => { + console.error("\n✗ Unerwarteter Fehler im Smoke-Test:", err); + process.exit(1); + }); diff --git a/scripts/test-identity-account.ts b/scripts/test-identity-account.ts new file mode 100644 index 0000000..ca17c0c --- /dev/null +++ b/scripts/test-identity-account.ts @@ -0,0 +1,93 @@ +// WS4-Abnahmetest (Option C) — Passwort/Reset/Session-Kill-Switch an der Identity. +// +// Prüft, dass die Self-Service-/Reset-Bausteine auf der GLOBALEN Identity arbeiten +// (nicht mehr auf der per-Mandant-Mitgliedschaft): +// 1. findAccountByEmail("tenant") liefert die Identity (id === Identity.id). +// 2. writePasswordHash/readPasswordHash operieren auf der Identity; ein neuer +// Hash wirkt sofort im Login (authorizeTenantCredentials). +// 3. invalidateSessions({type:"identity"}) setzt die Kill-Switch-Marke an der Identity. +// 4. Der Mandanten-Admin-Reset (resetUserPassword/resetTenantUserPassword) ist +// entfernt — durch tsc/lint bereits abgesichert (keine Referenzen mehr). +// +// Lauf: npx tsx scripts/test-identity-account.ts (setzt den Demo-Seed voraus) + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { hashPassword, verifyPassword } from "../src/server/password"; +import { authorizeTenantCredentials } from "../src/server/auth"; +import { findAccountByEmail, readPasswordHash, writePasswordHash } from "../src/server/auth-selfservice"; +import { invalidateSessions, getSessionsValidAfter } from "../src/server/sessions"; + +const EMAIL = "ws4-account@demo.example"; +const PW1 = "Start-Passwort-1!"; +const PW2 = "Neues-Passwort-2!"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function cleanup() { + await prisma.user.deleteMany({ where: { email: EMAIL } }); + await prisma.identity.deleteMany({ where: { email: EMAIL } }); +} + +async function main() { + await cleanup(); + const demo = await prisma.tenant.findUniqueOrThrow({ where: { slug: "demo" } }); + const role = await prisma.role.findFirst({ where: { tenantId: demo.id, key: "user" } }); + const identity = await prisma.identity.create({ data: { email: EMAIL, passwordHash: await hashPassword(PW1) } }); + await prisma.user.create({ + data: { + tenantId: demo.id, identityId: identity.id, email: EMAIL, name: "WS4 Konto", + status: "ACTIVE", ...(role ? { userRoles: { create: [{ roleId: role.id }] } } : {}), + }, + }); + + console.log("\n— 1) findAccountByEmail liefert die Identity —"); + const acc = await findAccountByEmail("tenant", EMAIL); + ok(acc?.id === identity.id, `Account.id === Identity.id (${acc?.id === identity.id})`); + ok(acc?.email === EMAIL, "Account.email = Identity.email"); + + console.log("\n— 2) Passwort lebt an der Identity; Login nutzt es —"); + const loginOld = await authorizeTenantCredentials({ email: EMAIL, password: PW1, tenant: "demo" }); + ok(!!loginOld && loginOld.identityId === identity.id, "Login mit Start-Passwort erfolgreich"); + + // Passwort an der Identity ändern (Reset-Baustein). + await writePasswordHash("tenant", identity.id, await hashPassword(PW2)); + const storedHash = await readPasswordHash("tenant", identity.id); + ok(!!storedHash && (await verifyPassword(storedHash, PW2)), "readPasswordHash liefert den neuen Identity-Hash"); + + const loginOldAfter = await authorizeTenantCredentials({ email: EMAIL, password: PW1, tenant: "demo" }); + ok(loginOldAfter === null, "altes Passwort funktioniert nach Änderung NICHT mehr"); + const loginNew = await authorizeTenantCredentials({ email: EMAIL, password: PW2, tenant: "demo" }); + ok(!!loginNew, "neues Passwort funktioniert sofort (Passwort an Identity, nicht Membership)"); + + console.log("\n— 3) Session-Kill-Switch an der Identity —"); + const before = await getSessionsValidAfter({ type: "identity", id: identity.id }); + ok(before === null, "vor Invalidierung keine Marke"); + await invalidateSessions({ type: "identity", id: identity.id }); + const after = await getSessionsValidAfter({ type: "identity", id: identity.id }); + ok(after instanceof Date, "invalidateSessions setzt sessionsValidAfter an der Identity"); + // Der Kill-Switch existiert NUR an der Identity — die Membership hat kein solches Feld + // mehr (Contract-Migration hat die User-Auth-Spalten entfernt). + + await cleanup(); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-identity-login.ts b/scripts/test-identity-login.ts new file mode 100644 index 0000000..efdcac3 --- /dev/null +++ b/scripts/test-identity-login.ts @@ -0,0 +1,83 @@ +// WS1-Abnahmetest (Option C) — Mandanten-Login gegen die globale Identity. +// +// Prüft `authorizeTenantCredentials` (src/server/auth.ts) gegen die Seed-DB: +// 1. Single-Membership: admin@demo (ohne Slug) landet in seinem Mandanten. +// 2. Falsches Passwort → null (kein Login). +// 3. Multi-Membership OHNE Slug → null (Auswahlseite /select-tenant = WS2). +// 4. Multi-Membership MIT Slug → richtiger Mandant + mandantenspezifische Rechte. +// 5. Falscher/fremder Slug → null. +// 6. Unbekannte E-Mail → null. +// 7. Session-Shape trägt identityId, activeMembershipId und memberships[]. +// +// Lauf: npx tsx scripts/test-identity-login.ts (setzt den Demo-Seed voraus) + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { authorizeTenantCredentials } from "../src/server/auth"; + +const PW = "Demo1234!"; +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function main() { + console.log("\n— 1) Single-Membership: admin@demo ohne Slug —"); + const admin = await authorizeTenantCredentials({ email: "admin@demo.example", password: PW }); + ok(!!admin, "admin@demo meldet sich an"); + ok(admin?.tenantSlug === "demo", `aktiver Mandant = demo (${admin?.tenantSlug})`); + ok(!!admin?.identityId, "Session trägt identityId"); + ok(admin?.activeMembershipId === admin?.id, "activeMembershipId = User.id der Mitgliedschaft"); + ok((admin?.memberships?.length ?? 0) === 1, `memberships-Liste = 1 (${admin?.memberships?.length})`); + ok(admin?.roles.includes("tenant-admin") ?? false, "Rolle tenant-admin im aktiven Mandanten"); + + console.log("\n— 2) Falsches Passwort → null —"); + const wrong = await authorizeTenantCredentials({ email: "admin@demo.example", password: "falsch!!" }); + ok(wrong === null, "falsches Passwort ⇒ null"); + // Zähler zurücksetzen, damit wiederholte Läufe die Identity nicht sperren. + await prisma.identity.update({ where: { email: "admin@demo.example" }, data: { failedLogins: 0, lockedUntil: null } }); + + console.log("\n— 3) Multi-Membership ohne Slug → Session ohne aktiven Mandanten (WS2) —"); + const noTenant = await authorizeTenantCredentials({ email: "multi@demo.example", password: PW }); + ok(!!noTenant && noTenant.tenantId === "", "multi@ ohne Slug ⇒ Session ohne aktiven Mandanten (tenantId leer → /select-tenant)"); + ok((noTenant?.memberships?.length ?? 0) === 2, `memberships-Liste = 2 im No-Tenant-State (${noTenant?.memberships?.length})`); + + console.log("\n— 4) Multi-Membership mit Slug → korrekter Mandant + Rechte —"); + const inDemo2 = await authorizeTenantCredentials({ email: "multi@demo.example", password: PW, tenant: "demo2" }); + ok(inDemo2?.tenantSlug === "demo2", `Slug demo2 ⇒ aktiver Mandant demo2 (${inDemo2?.tenantSlug})`); + ok(inDemo2?.roles.includes("tenant-admin") ?? false, "in demo2: Rolle tenant-admin"); + ok((inDemo2?.memberships?.length ?? 0) === 2, `memberships-Liste = 2 (${inDemo2?.memberships?.length})`); + + const inDemo = await authorizeTenantCredentials({ email: "multi@demo.example", password: PW, tenant: "demo" }); + ok(inDemo?.tenantSlug === "demo", `Slug demo ⇒ aktiver Mandant demo (${inDemo?.tenantSlug})`); + ok(inDemo?.roles.includes("user") ?? false, "in demo: Rolle user"); + // Rechte je aktivem Mandant verschieden (tenant-admin demo2 ≠ user demo). + ok( + JSON.stringify([...(inDemo?.permissions ?? [])].sort()) !== JSON.stringify([...(inDemo2?.permissions ?? [])].sort()), + "Rechte je aktivem Mandant verschieden (demo user ≠ demo2 admin)" + ); + + console.log("\n— 5) Fremder/falscher Slug → null —"); + const wrongSlug = await authorizeTenantCredentials({ email: "admin@demo.example", password: PW, tenant: "gibtsnicht" }); + ok(wrongSlug === null, "unbekannter Slug ⇒ null"); + + console.log("\n— 6) Unbekannte E-Mail → null —"); + const unknown = await authorizeTenantCredentials({ email: "gibtsnicht@demo.example", password: PW }); + ok(unknown === null, "unbekannte E-Mail ⇒ null"); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-identity-schema.ts b/scripts/test-identity-schema.ts new file mode 100644 index 0000000..97e3426 --- /dev/null +++ b/scripts/test-identity-schema.ts @@ -0,0 +1,123 @@ +// WS0-Abnahmetest (Option C — "Zentrale Identität mit Mandanten-Mitgliedschaften"). +// +// Weist die "Goldenen Regeln" des Fundament-Umbaus auf DB-Ebene nach: +// 1. `identities` ist GLOBAL: KEIN tenant_id, KEINE RLS-Policy. +// 2. Jede Mitgliedschaft (`users`) verweist auf genau eine Identity (identity_id NOT NULL). +// 3. Eine Person hat je Mandant höchstens EINE Mitgliedschaft (@@unique(tenant,identity)). +// 4. Multi-Membership-Fixture: eine Identity ist in ZWEI Mandanten mit je eigener Rolle. +// 5. Login-Quelle ist Identity: identity.findUnique({email}) liefert passwordHash +// über den rohen (Owner-)`prisma`-Client — ohne Mandantenkontext. +// 6. Expand/Contract: WebAuthn hängt in WS0 noch an `users` (tenant-gebunden) — der +// Umzug auf die Identity ist bewusst WS4 (dieser Test darf nach WS4 angepasst werden). +// +// Lauf: npx tsx scripts/test-identity-schema.ts +// Nutzt die lokale Postgres-DB (Container isms-tool-postgres-1); .env liegt im Worktree. +// Setzt den Demo-Seed voraus (npx tsx prisma/seed.ts). + +import "dotenv/config"; +import { prisma } from "../src/server/db"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function expectThrow(fn: () => Promise, msg: string) { + try { + await fn(); + ok(false, `${msg} — kein Throw`); + } catch { + ok(true, msg); + } +} + +async function count(sql: string): Promise { + const r = await prisma.$queryRawUnsafe<{ c: number }[]>(sql); + return Number(r[0].c); +} + +async function main() { + console.log("\n— Regel 1: identities ist global (kein tenant_id, keine RLS-Policy) —"); + const hasTenantCol = await count( + `SELECT count(*)::int AS c FROM information_schema.columns WHERE table_name = 'identities' AND column_name = 'tenant_id'` + ); + ok(hasTenantCol === 0, "identities hat KEINE tenant_id-Spalte"); + const policies = await count(`SELECT count(*)::int AS c FROM pg_policies WHERE tablename = 'identities'`); + ok(policies === 0, "identities hat KEINE RLS-Policy"); + const rlsForced = await count( + `SELECT count(*)::int AS c FROM pg_class WHERE relname = 'identities' AND (relrowsecurity OR relforcerowsecurity)` + ); + ok(rlsForced === 0, "identities hat RLS weder ENABLED noch FORCED"); + + console.log("\n— Regel 2: jede Mitgliedschaft hat eine Identity —"); + const orphan = await count(`SELECT count(*)::int AS c FROM users WHERE identity_id IS NULL`); + ok(orphan === 0, "keine users-Zeile ohne identity_id"); + const memberships = await prisma.user.count(); + ok(memberships > 0, `Mitgliedschaften vorhanden (${memberships})`); + + console.log("\n— Regel 3: @@unique(tenant_id, identity_id) verhindert Doppel-Mitgliedschaft —"); + const demo = await prisma.tenant.findUniqueOrThrow({ where: { slug: "demo" } }); + const multi = await prisma.identity.findUniqueOrThrow({ where: { email: "multi@demo.example" } }); + // multi@ ist bereits Mitglied in "demo" → ein zweiter Datensatz muss am Unique scheitern. + await expectThrow( + () => + prisma.user.create({ + data: { + tenantId: demo.id, + identityId: multi.id, + email: "dup-membership@demo.example", + name: "Duplikat", + }, + }), + "zweite Mitgliedschaft (demo, multi) → Unique-Verstoß" + ); + + console.log("\n— Regel 4: Multi-Membership-Fixture über zwei Mandanten —"); + const multiFull = await prisma.identity.findUniqueOrThrow({ + where: { email: "multi@demo.example" }, + include: { memberships: { include: { tenant: true, userRoles: { include: { role: true } } } } }, + }); + const slugs = multiFull.memberships.map((m) => m.tenant.slug).sort(); + ok(slugs.length >= 2 && slugs.includes("demo") && slugs.includes("demo2"), `multi@ ist in ≥2 Mandanten (${slugs.join(", ")})`); + const rolesByTenant = Object.fromEntries( + multiFull.memberships.map((m) => [m.tenant.slug, m.userRoles.map((r) => r.role.key).sort()]) + ); + ok( + JSON.stringify(rolesByTenant.demo) !== JSON.stringify(rolesByTenant.demo2), + `Rollen je Mandant verschieden (demo=${JSON.stringify(rolesByTenant.demo)}, demo2=${JSON.stringify(rolesByTenant.demo2)})` + ); + + console.log("\n— Regel 5: Login-Quelle ist Identity (Owner-Client, ohne Mandantenkontext) —"); + const admin = await prisma.identity.findUnique({ where: { email: "admin@demo.example" } }); + ok(!!admin && admin.passwordHash.length > 0, "identity.findUnique({email}) liefert passwordHash"); + const singleAdminMemberships = await prisma.user.count({ where: { identity: { email: "admin@demo.example" } } }); + ok(singleAdminMemberships === 1, `admin@ bleibt single-membership (Ein-Schritt-Login heil): ${singleAdminMemberships}`); + + console.log("\n— Regel 6: WebAuthn ist identitätsgebunden (WS4b) —"); + const waTenantCol = await count( + `SELECT count(*)::int AS c FROM information_schema.columns WHERE table_name = 'webauthn_credentials' AND column_name = 'tenant_id'` + ); + ok(waTenantCol === 0, "webauthn_credentials hat KEINE tenant_id mehr"); + const waIdentityCol = await count( + `SELECT count(*)::int AS c FROM information_schema.columns WHERE table_name = 'webauthn_credentials' AND column_name = 'identity_id'` + ); + ok(waIdentityCol === 1, "webauthn_credentials trägt identity_id"); + const waPolicies = await count(`SELECT count(*)::int AS c FROM pg_policies WHERE tablename = 'webauthn_credentials'`); + ok(waPolicies === 0, "webauthn_credentials hat KEINE RLS-Policy mehr"); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-incident-deadlines.ts b/scripts/test-incident-deadlines.ts new file mode 100644 index 0000000..775e972 --- /dev/null +++ b/scripts/test-incident-deadlines.ts @@ -0,0 +1,205 @@ +// Reiner Test der Fristen-/Timer-Logik für Vorfälle (IM-B, Fachkonzept §6). +// +// Prüft: +// 1. Fristen aus dem Kenntniszeitpunkt (detectedAt/reportedAt) korrekt berechnet. +// 2. NIS2-Timer greifen NUR bei nis2Category ∈ {wichtig, wesentlich} UND nis2Relevant. +// 3. DSGVO-Frist (72 h) greift bei Personenbezug (dsgvoRelevant). +// 4. Interne SLA je Severity (Reaktions-/Behebungsfrist). +// 5. Überfällig-Erkennung + offene/erledigte Meldestufen (reportStatus). +// +// Lauf: npx tsx scripts/test-incident-deadlines.ts (rein, keine DB). + +import { + addHours, + addMonths, + computeDeadlines, + computeSla, + deadlineItems, + isDueSoon, + isOverdue, + isReportable, + knowledgeTime, + nextReportStatus, + nis2TimersApply, + openReportDeadlines, + remainingMs, + slaForSeverity, + stageDone, + NIS2_ERSTMELDUNG_HOURS, + NIS2_FOLGEMELDUNG_HOURS, +} from "../src/lib/incident-deadlines"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const HOUR = 3_600_000; +const known = new Date("2026-03-10T08:00:00.000Z"); + +// ── 1. Kenntniszeitpunkt-Priorität ────────────────────────────────────────── +{ + const detected = new Date("2026-03-10T08:00:00Z"); + const reported = new Date("2026-03-11T08:00:00Z"); + ok( + knowledgeTime({ detectedAt: detected, reportedAt: reported })?.getTime() === detected.getTime(), + "knowledgeTime: detectedAt hat Vorrang vor reportedAt", + ); + ok( + knowledgeTime({ detectedAt: null, reportedAt: reported })?.getTime() === reported.getTime(), + "knowledgeTime: ohne detectedAt greift reportedAt", + ); + ok( + knowledgeTime({ detectedAt: null, reportedAt: null, occurredAt: null, createdAt: known })?.getTime() === + known.getTime(), + "knowledgeTime: Fallback auf createdAt", + ); +} + +// ── 1b. Fristen aus Kenntniszeitpunkt (NIS2 wesentlich) ───────────────────── +{ + const d = computeDeadlines({ + nis2Category: "wesentlich", + nis2Relevant: true, + dsgvoRelevant: false, + knownAt: known, + }); + ok( + d.erstmeldungDueAt?.getTime() === known.getTime() + NIS2_ERSTMELDUNG_HOURS * HOUR, + "NIS2 Erstmeldung = Kenntnis + 24 h", + ); + ok( + d.folgemeldungDueAt?.getTime() === known.getTime() + NIS2_FOLGEMELDUNG_HOURS * HOUR, + "NIS2 Folgemeldung = Kenntnis + 72 h", + ); + ok(d.abschlussDueAt !== null, "NIS2 Abschlussbericht gesetzt"); + ok( + d.abschlussDueAt!.getMonth() === addMonths(known, 1).getMonth(), + "NIS2 Abschlussbericht = Kenntnis + 1 Monat (Monat +1)", + ); + ok(d.dsgvoDueAt === null, "ohne Personenbezug keine DSGVO-Frist"); +} + +// ── 2. NIS2-Timer nur bei passender Kategorie UND Relevanz ────────────────── +{ + ok(nis2TimersApply("wichtig", true), "nis2TimersApply: wichtig + relevant → true"); + ok(nis2TimersApply("wesentlich", true), "nis2TimersApply: wesentlich + relevant → true"); + ok(!nis2TimersApply("keine", true), "nis2TimersApply: keine → false (auch wenn relevant)"); + ok(!nis2TimersApply("wesentlich", false), "nis2TimersApply: nicht relevant → false"); + + const noCat = computeDeadlines({ + nis2Category: "keine", + nis2Relevant: true, + dsgvoRelevant: false, + knownAt: known, + }); + ok( + noCat.erstmeldungDueAt === null && noCat.folgemeldungDueAt === null && noCat.abschlussDueAt === null, + "computeDeadlines: nis2Category=keine → keine NIS2-Fristen", + ); + + const notRelevant = computeDeadlines({ + nis2Category: "wesentlich", + nis2Relevant: false, + dsgvoRelevant: false, + knownAt: known, + }); + ok( + notRelevant.erstmeldungDueAt === null, + "computeDeadlines: nis2Relevant=false → keine NIS2-Fristen (trotz Kategorie)", + ); +} + +// ── 3. DSGVO bei Personenbezug ────────────────────────────────────────────── +{ + const d = computeDeadlines({ + nis2Category: "keine", + nis2Relevant: false, + dsgvoRelevant: true, + knownAt: known, + }); + ok(d.dsgvoDueAt?.getTime() === known.getTime() + 72 * HOUR, "DSGVO-Frist = Kenntnis + 72 h"); + ok(d.erstmeldungDueAt === null, "DSGVO ohne NIS2: keine NIS2-Fristen"); + ok( + isReportable({ nis2Category: "keine", nis2Relevant: false, dsgvoRelevant: true }), + "isReportable: nur DSGVO → meldepflichtig", + ); + ok( + !isReportable({ nis2Category: "keine", nis2Relevant: true, dsgvoRelevant: false }), + "isReportable: NIS2-relevant aber Kategorie keine → nicht meldepflichtig", + ); +} + +// ── 4. Interne SLA je Severity ────────────────────────────────────────────── +{ + ok(slaForSeverity("kritisch").reactionHours === 1, "SLA kritisch: Reaktion 1 h"); + ok(slaForSeverity("kritisch").resolutionHours === 24, "SLA kritisch: Behebung 24 h"); + ok( + slaForSeverity("niedrig").reactionHours > slaForSeverity("hoch").reactionHours, + "SLA: niedrigere Severity → längere Reaktionsfrist", + ); + const sla = computeSla("hoch", known); + ok( + sla.reactionDueAt?.getTime() === addHours(known, 4).getTime(), + "computeSla hoch: Reaktionsfrist = Kenntnis + 4 h", + ); + ok(computeSla("mittel", null).reactionDueAt === null, "computeSla ohne Kenntnis → null"); +} + +// ── 5. Überfällig-Erkennung + Meldestufen ─────────────────────────────────── +{ + const now = new Date("2026-03-11T10:00:00.000Z"); // 26 h nach Kenntnis + ok(isOverdue(addHours(known, 24), now), "isOverdue: 24-h-Frist ist nach 26 h überfällig"); + ok(!isOverdue(addHours(known, 72), now), "isOverdue: 72-h-Frist noch nicht überfällig"); + ok(remainingMs(addHours(known, 72), now)! > 0, "remainingMs: 72-h-Frist hat positive Restzeit"); + ok(isDueSoon(addHours(known, 30), now), "isDueSoon: Frist in 4 h ist bald fällig"); + ok(!isDueSoon(addHours(known, 240), now), "isDueSoon: Frist in >24 h ist nicht bald fällig"); + + ok(stageDone("erstmeldung", "erstmeldung"), "stageDone: reportStatus=erstmeldung → Erstmeldung erledigt"); + ok(!stageDone("pruefung", "erstmeldung"), "stageDone: reportStatus=pruefung → Erstmeldung offen"); + ok(stageDone("folgemeldung", "erstmeldung"), "stageDone: reportStatus=folgemeldung → Erstmeldung erledigt"); + + const inc = { + severity: "hoch", + reportStatus: "pruefung", + detectedAt: known, + reportedAt: null, + occurredAt: null, + createdAt: known, + erstmeldungDueAt: addHours(known, 24), + folgemeldungDueAt: addHours(known, 72), + abschlussDueAt: addMonths(known, 1), + dsgvoDueAt: null, + }; + const items = deadlineItems(inc, now); + const erst = items.find((i) => i.kind === "erstmeldung")!; + ok(erst.overdue, "deadlineItems: offene Erstmeldung nach 26 h ist überfällig"); + ok(items.some((i) => i.kind === "reaction"), "deadlineItems: interne SLA-Reaktionsfrist enthalten"); + + const open = openReportDeadlines(inc, now); + ok( + open.every((i) => !i.done) && open.some((i) => i.kind === "erstmeldung"), + "openReportDeadlines: nur offene Meldestufen, Erstmeldung enthalten", + ); + + const submitted = openReportDeadlines({ ...inc, reportStatus: "folgemeldung" }, now); + ok( + !submitted.some((i) => i.kind === "erstmeldung" || i.kind === "folgemeldung"), + "openReportDeadlines: eingereichte Stufen (reportStatus=folgemeldung) fallen raus", + ); +} + +// ── 6. Meldung-Track Vorwärts-Übergänge ───────────────────────────────────── +{ + ok(nextReportStatus("pruefung") === "erstmeldung", "nextReportStatus: pruefung → erstmeldung"); + ok(nextReportStatus("erstmeldung") === "folgemeldung", "nextReportStatus: erstmeldung → folgemeldung"); + ok(nextReportStatus("folgemeldung") === "abschluss", "nextReportStatus: folgemeldung → abschluss"); + ok(nextReportStatus("abschluss") === null, "nextReportStatus: abschluss ist Endzustand"); +} + +if (failures) { + console.error(`\n✗ ${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(1); +} +console.log("\n✓ Alle Fristen-/Timer-Prüfungen bestanden."); diff --git a/scripts/test-incident-inbound.ts b/scripts/test-incident-inbound.ts new file mode 100644 index 0000000..54d7258 --- /dev/null +++ b/scripts/test-incident-inbound.ts @@ -0,0 +1,179 @@ +// Reiner Test der Inbound-Mail-Logik für Vorfälle (IM-D, Fachkonzept §2/§14.3). +// +// Prüft parse.ts + route.ts OHNE Netz/DB/IMAP (Fixtures): +// 1. Token wird aus Delivered-To/X-Envelope-To gezogen — NICHT aus To (Weiterleitung). +// 2. Weiterleitung: SPF-Fail wird toleriert, DKIM-pass + Allowlist tragen → Vorfall. +// 3. Auto-Reply/Bounce (Auto-Submitted/Precedence/leerer Return-Path) → ignorieren. +// 4. Dedupe per Message-ID (alreadySeen) → ignorieren. +// 5. Unbekannter Token → Betreiber-Review (nicht droppen). +// 6. Kein Token → Betreiber-Review. +// 7. Absender nicht in Allowlist → Review (fail-closed). +// 8. DKIM=fail → Review (auch bei getroffener Allowlist). +// +// Lauf: npx tsx scripts/test-incident-inbound.ts (rein, keine DB). + +import { + parseInbound, + deliveryRecipients, + tokenFromAddress, + isAutoSubmitted, + authResults, + intakeAddress, + type RawHeaders, +} from "../src/server/incident-inbound/parse"; +import { decideRoute, generateIntakeToken, type IntakeConfigView } from "../src/server/incident-inbound/route"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const DOMAIN = "in.certvia.de"; +const TOKEN = "abc123def456"; // passt auf [a-z0-9]{8,64} +const INTAKE = intakeAddress(TOKEN, DOMAIN); // vorfall-abc123def456@in.certvia.de + +const config: IntakeConfigView = { + tenantId: "tenant-1", + token: TOKEN, + allowlistDomains: ["kunde.de"], + sourceAddress: "vorfall@kunde.de", +}; + +// Hilfsbau einer Fixture-Mail. +function mail(headers: RawHeaders, extra: Partial<{ from: string; subject: string; text: string; messageId: string }> = {}) { + return parseInbound({ headers, ...extra }, DOMAIN); +} + +// --- 1) Token aus Delivered-To / X-Envelope-To, nicht aus To ------------------- +{ + const parsed = mail( + { + "To": "vorfall@kunde.de", // Kundenadresse — hier steht KEIN Token + "Delivered-To": INTAKE, // Zustelladresse trägt den Token + "From": "Melder ", + "Message-ID": "", + "Authentication-Results": "mx.certvia.de; dkim=pass header.d=kunde.de; spf=fail", + }, + { subject: "Serverausfall", text: "Bitte prüfen." }, + ); + ok(parsed.token === TOKEN, "Token wird aus Delivered-To gezogen"); + ok(parsed.recipientForToken === INTAKE, "recipientForToken = Intake-Adresse"); + ok(tokenFromAddress("vorfall@kunde.de", DOMAIN) === null, "To-Adresse liefert keinen Token"); + ok(deliveryRecipients({ To: "vorfall@kunde.de" }).length === 0, "To zählt nicht als Zustell-Empfänger"); +} + +// --- 2) Weiterleitung: SPF-Fail toleriert, DKIM+Allowlist → Vorfall ------------ +{ + const parsed = mail( + { + "X-Envelope-To": INTAKE, + "From": "Alice ", + "Message-ID": "", + "Authentication-Results": "mx; dkim=pass; spf=fail", // Weiterleitung bricht SPF + }, + { subject: "Phishing gemeldet", text: "Verdächtige Mail erhalten." }, + ); + ok(parsed.spf === "fail" && parsed.dkim === "pass", "SPF=fail, DKIM=pass erkannt"); + const d = decideRoute(parsed, { config, alreadySeen: false }); + ok(d.action === "incident", "trotz SPF-Fail → Vorfall (DKIM+Allowlist tragen)"); + if (d.action === "incident") { + ok(d.incident.tenantId === "tenant-1", "Vorfall im richtigen Mandanten"); + ok(d.incident.title === "Phishing gemeldet", "Betreff → Titel"); + ok(d.incident.reporterContact === "alice@kunde.de", "Absender → Melder-Kontakt"); + ok(d.spfWarning === true, "SPF-Fail als Warnung markiert (nicht blockierend)"); + ok(d.incident.inboundMessageId === "m2@kunde.de", "Message-ID normalisiert übernommen"); + } +} + +// --- 3) Auto-Reply / Bounce → ignorieren -------------------------------------- +{ + ok(isAutoSubmitted({ "Auto-Submitted": "auto-replied" }), "Auto-Submitted erkannt"); + ok(isAutoSubmitted({ "Precedence": "bulk" }), "Precedence: bulk erkannt"); + ok(isAutoSubmitted({ "Return-Path": "<>" }), "Leerer Return-Path (Bounce) erkannt"); + ok(!isAutoSubmitted({ "Auto-Submitted": "no" }), "Auto-Submitted: no ist normal"); + + const parsed = mail({ + "Delivered-To": INTAKE, + "From": "mailer@kunde.de", + "Auto-Submitted": "auto-replied", + "Message-ID": "", + "Authentication-Results": "mx; dkim=pass; spf=pass", + }); + const d = decideRoute(parsed, { config, alreadySeen: false }); + ok(d.action === "ignore" && d.reason === "auto_submitted", "Auto-Reply → ignore"); +} + +// --- 4) Dedupe per Message-ID → ignorieren ------------------------------------ +{ + const parsed = mail({ + "Delivered-To": INTAKE, + "From": "alice@kunde.de", + "Message-ID": "", + "Authentication-Results": "mx; dkim=pass; spf=pass", + }); + const d = decideRoute(parsed, { config, alreadySeen: true }); + ok(d.action === "ignore" && d.reason === "duplicate", "bereits gesehene Message-ID → ignore"); +} + +// --- 5) Unbekannter Token → Review -------------------------------------------- +{ + const parsed = mail({ + "Delivered-To": intakeAddress("unknowntoken99", DOMAIN), + "From": "alice@kunde.de", + "Message-ID": "", + "Authentication-Results": "mx; dkim=pass; spf=pass", + }); + ok(parsed.token === "unknowntoken99", "Token geparst, aber unbekannt"); + const d = decideRoute(parsed, { config: null, alreadySeen: false }); + ok(d.action === "review" && d.review.reason === "unknown_token", "unbekannter Token → Review"); + ok(d.action === "review" && d.review.tenantId === null, "kein Mandant bei unbekanntem Token"); +} + +// --- 6) Kein Token → Review --------------------------------------------------- +{ + const parsed = mail({ + "Delivered-To": "hallo@in.certvia.de", // kein vorfall- + "From": "alice@kunde.de", + "Message-ID": "", + }); + ok(parsed.token === null, "kein Token erkannt"); + const d = decideRoute(parsed, { config: null, alreadySeen: false }); + ok(d.action === "review" && d.review.reason === "no_token", "kein Token → Review"); +} + +// --- 7) Absender nicht in Allowlist → Review (fail-closed) -------------------- +{ + const parsed = mail({ + "Delivered-To": INTAKE, + "From": "fremd@boese.example", // nicht in Allowlist (kunde.de) + "Message-ID": "", + "Authentication-Results": "mx; dkim=pass; spf=pass", + }); + const d = decideRoute(parsed, { config, alreadySeen: false }); + ok(d.action === "review" && d.review.reason === "allowlist_failed", "Absender außerhalb Allowlist → Review"); + ok(d.action === "review" && d.review.tenantId === "tenant-1", "Mandant trotzdem aufgelöst (Token bekannt)"); +} + +// --- 8) DKIM=fail → Review (auch bei getroffener Allowlist) ------------------- +{ + const parsed = mail({ + "Delivered-To": INTAKE, + "From": "alice@kunde.de", + "Message-ID": "", + "Authentication-Results": "mx; dkim=fail; spf=pass", + }); + ok(authResults({ "Authentication-Results": "mx; dkim=fail" }).dkim === "fail", "DKIM=fail geparst"); + const d = decideRoute(parsed, { config, alreadySeen: false }); + ok(d.action === "review" && d.review.reason === "dkim_failed", "DKIM-Fail → Review"); +} + +// --- 9) Token-Generator liefert gültiges Format ------------------------------- +{ + const tok = generateIntakeToken(); + ok(/^[a-z0-9]{8,64}$/.test(tok), "generateIntakeToken erfüllt Token-Format"); + ok(tokenFromAddress(intakeAddress(tok, DOMAIN), DOMAIN) === tok, "Round-Trip Token↔Adresse"); +} + +console.log(failures === 0 ? "\nAlle Inbound-Tests grün." : `\n${failures} Test(s) fehlgeschlagen.`); +process.exit(failures === 0 ? 0 : 1); diff --git a/scripts/test-incident-links.ts b/scripts/test-incident-links.ts new file mode 100644 index 0000000..4f9dade --- /dev/null +++ b/scripts/test-incident-links.ts @@ -0,0 +1,212 @@ +// Akzeptanztest Modul „Vorfälle" (IM-C): Verknüpfungen, Abschluss-Pflicht & Export. +// +// Prüft: +// 1. Maßnahme direkt aus dem Vorfall anlegen → landet im ZENTRALEN Maßnahmen-Modul +// (measures-Tabelle) UND ist mit dem Vorfall verknüpft (IncidentMeasure). +// 2. Risiko neu aus dem Vorfall erzeugen → im Risiko-Register + verknüpft (IncidentRisk). +// 3. Nachweis anlegen + verknüpfen (Evidence + IncidentEvidence). +// 4. Abschluss-Pflichtfelder (§8): abgeschlossen erzwingt Ursache/Lösung/Lessons +// Learned (+ Abschlussnotiz); Post-Incident-Review/Wirksamkeit sind NICHT Pflicht. +// 5. Register-Export (CSV) enthält die erwarteten Spalten/Werte. +// 6. NIS2- und DSGVO-Meldevorlagen sind vorbefüllt (Zeiten, Kategorie, Fristen). +// +// Lauf: npx tsx scripts/test-incident-links.ts (lokale isms-DB, .env im Repo). + +import "dotenv/config"; +import { prisma, dbForTenant } from "../src/server/db"; +import { nextIncidentRefNo } from "../src/server/incident-refno"; +import { missingRequiredFields } from "../src/lib/incident"; +import { + INCIDENT_REGISTER_COLUMNS, + toRegisterCsv, + buildNis2Template, + buildDsgvoTemplate, + type IncidentRegisterInput, + type IncidentTemplateInput, +} from "../src/lib/incident-export"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const SLUG = "zz-inc-links-a"; +const EMAIL = "zz-inc-links-owner@test.example"; + +async function cleanup() { + const t = await prisma.tenant.findFirst({ where: { slug: SLUG }, select: { id: true } }); + if (t) { + await prisma.incident.deleteMany({ where: { tenantId: t.id } }); + await prisma.measure.deleteMany({ where: { tenantId: t.id } }); + await prisma.risk.deleteMany({ where: { tenantId: t.id } }); + await prisma.evidence.deleteMany({ where: { tenantId: t.id } }); + await prisma.user.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); + } + await prisma.identity.deleteMany({ where: { email: EMAIL } }); +} + +async function nextMeasureRef(tenantId: string) { + const last = await prisma.measure.aggregate({ where: { tenantId }, _max: { refNo: true } }); + return (last._max.refNo ?? 0) + 1; +} +async function nextRiskRef(tenantId: string) { + const last = await prisma.risk.aggregate({ where: { tenantId }, _max: { refNo: true } }); + return (last._max.refNo ?? 0) + 1; +} + +async function main() { + await cleanup(); + + const tenant = await prisma.tenant.create({ data: { name: "IM-C Test", slug: SLUG } }); + const identity = await prisma.identity.create({ data: { email: EMAIL, passwordHash: "x" } }); + const user = await prisma.user.create({ data: { tenantId: tenant.id, identityId: identity.id, email: EMAIL, name: "Owner" } }); + const db = dbForTenant(tenant.id); + + const occurredAt = new Date("2026-08-15T08:00:00Z"); + const detectedAt = new Date("2026-08-16T09:30:00Z"); + const incident = await db.incident.create({ + data: { + tenantId: tenant.id, + refNo: await nextIncidentRefNo(prisma, tenant.id), + title: "Ransomware auf Fileserver", + description: "Verschlüsselte Freigaben; Verdacht auf Datenabfluss.", + category: "malware", + severity: "hoch", + status: "in_bearbeitung", + occurredAt, + detectedAt, + impactC: 3, + impactI: 4, + impactA: 4, + urgency: 4, + affectedDataCategories: ["Kundendaten", "Zugangsdaten"], + personalData: true, + dsgvoRelevant: true, + nis2Relevant: true, + ownerId: user.id, + // Meldefristen wie von IM-B aus dem Kenntniszeitpunkt gesetzt (24h/72h/1M). + erstmeldungDueAt: new Date(detectedAt.getTime() + 24 * 3600_000), + folgemeldungDueAt: new Date(detectedAt.getTime() + 72 * 3600_000), + dsgvoDueAt: new Date(detectedAt.getTime() + 72 * 3600_000), + reportStatus: "pruefung", + }, + }); + + // ── 1. Maßnahme direkt aus dem Vorfall anlegen + verknüpfen ──────────────── + const measure = await db.measure.create({ + data: { tenantId: tenant.id, refNo: await nextMeasureRef(tenant.id), title: "Systeme isolieren & Backups prüfen", priority: "HIGH", ownerId: user.id, createdBy: user.id }, + }); + await db.incidentMeasure.create({ data: { tenantId: tenant.id, incidentId: incident.id, measureId: measure.id } }); + + const centralMeasure = await db.measure.findFirst({ where: { id: measure.id } }); + ok(!!centralMeasure && centralMeasure.tenantId === tenant.id, "Maßnahme liegt im zentralen Maßnahmen-Modul (measures-Tabelle)"); + const linkedMeasures = await db.incidentMeasure.findMany({ where: { incidentId: incident.id }, include: { measure: true } }); + ok(linkedMeasures.length === 1 && linkedMeasures[0].measure.title === measure.title, "Maßnahme ist mit dem Vorfall verknüpft (IncidentMeasure, Titel/Status aus dem Modul)"); + ok(linkedMeasures[0].measure.status === "OPEN" && linkedMeasures[0].measure.priority === "HIGH", "Verknüpfte Maßnahme trägt Status/Priorität aus dem Maßnahmen-Modul"); + + // ── 2. Risiko neu erzeugen + verknüpfen ──────────────────────────────────── + const risk = await db.risk.create({ + data: { tenantId: tenant.id, refNo: await nextRiskRef(tenant.id), title: "Unzureichende Backup-Isolierung", likelihood: 3, impact: 5, score: 15, createdBy: user.id }, + }); + await db.incidentRisk.create({ data: { tenantId: tenant.id, incidentId: incident.id, riskId: risk.id } }); + const centralRisk = await db.risk.findFirst({ where: { id: risk.id } }); + ok(!!centralRisk && centralRisk.score === 15, "Risiko im Register angelegt (score = E×S)"); + const linkedRisks = await db.incidentRisk.count({ where: { incidentId: incident.id } }); + ok(linkedRisks === 1, "Risiko ist mit dem Vorfall verknüpft (IncidentRisk)"); + + // ── 3. Nachweis anlegen + verknüpfen ─────────────────────────────────────── + const ev = await db.evidence.create({ data: { tenantId: tenant.id, title: "Forensik-Report Erstsichtung", kind: "record", createdById: user.id } }); + await db.incidentEvidence.create({ data: { tenantId: tenant.id, incidentId: incident.id, evidenceId: ev.id, note: "PDF im DMS" } }); + const linkedEv = await db.incidentEvidence.findMany({ where: { incidentId: incident.id }, include: { evidence: true } }); + ok(linkedEv.length === 1 && linkedEv[0].evidence.title === ev.title, "Nachweis verknüpft (IncidentEvidence)"); + + // ── 4. Abschluss-Pflichtfelder (§8) ──────────────────────────────────────── + const missWithout = missingRequiredFields("abgeschlossen", { rootCause: "x", resolution: "y", closingNote: "z", lessonsLearned: "" }); + ok(missWithout.includes("lessonsLearned"), "Abschluss erzwingt Lessons Learned (fehlt → blockiert)"); + const missAll = missingRequiredFields("abgeschlossen", { rootCause: "Ursache", resolution: "Lösung", closingNote: "Notiz", lessonsLearned: "LL", postIncidentReview: null, measuresEffectiveness: null }); + ok(missAll.length === 0, "Abschluss mit Ursache/Lösung/Abschlussnotiz/Lessons Learned zulässig — Review/Wirksamkeit NICHT erzwungen"); + + // ── 5. Register-Export (CSV) ─────────────────────────────────────────────── + const regInput: IncidentRegisterInput = { + refNo: incident.refNo, + title: incident.title, + category: incident.category, + severity: incident.severity, + priority: incident.priority, + status: incident.status, + source: incident.source, + occurredAt: incident.occurredAt, + detectedAt: incident.detectedAt, + reportedAt: incident.reportedAt, + ownerName: user.name, + assigneeName: null, + nis2Relevant: incident.nis2Relevant, + dsgvoRelevant: incident.dsgvoRelevant, + personalData: incident.personalData, + prototypeData: incident.prototypeData, + reportStatus: incident.reportStatus, + erstmeldungDueAt: incident.erstmeldungDueAt, + dsgvoDueAt: incident.dsgvoDueAt, + abschlussDueAt: incident.abschlussDueAt, + measureCount: 1, + riskCount: 1, + assetCount: 0, + controlCount: 0, + createdAt: incident.createdAt, + }; + const csv = toRegisterCsv([regInput]); + const header = csv.split("\r\n")[0]; + ok(INCIDENT_REGISTER_COLUMNS.every((c) => header.includes(c)), "Register-CSV enthält alle erwarteten Spalten (Kennung … Maßnahmen … Erstellt)"); + ok(csv.includes(incident.refNo) && csv.includes("Ransomware auf Fileserver"), "Register-CSV-Zeile enthält refNo + Titel"); + ok(csv.includes("Schadsoftware"), "Register-CSV übersetzt die Kategorie (Schadsoftware)"); + + // ── 6. Meldevorlagen (NIS2 / DSGVO) ──────────────────────────────────────── + const tmpl: IncidentTemplateInput = { + refNo: incident.refNo, + title: incident.title, + description: incident.description, + category: incident.category, + severity: incident.severity, + organisation: tenant.name, + occurredAt: incident.occurredAt, + detectedAt: incident.detectedAt, + reportedAt: incident.reportedAt, + impactC: incident.impactC, + impactI: incident.impactI, + impactA: incident.impactA, + affectedDataCategories: incident.affectedDataCategories, + personalData: incident.personalData, + nis2Relevant: incident.nis2Relevant, + reporterName: incident.reporterName, + reporterContact: incident.reporterContact, + erstmeldungDueAt: incident.erstmeldungDueAt, + folgemeldungDueAt: incident.folgemeldungDueAt, + abschlussDueAt: incident.abschlussDueAt, + dsgvoDueAt: incident.dsgvoDueAt, + }; + const nis2 = buildNis2Template(tmpl); + ok(nis2.includes("NIS2") && nis2.includes(incident.refNo) && nis2.includes("Schadsoftware"), "NIS2-Vorlage vorbefüllt (refNo + Kategorie)"); + ok(nis2.includes("24 h") && nis2.includes("72 h") && nis2.includes("1 Monat"), "NIS2-Vorlage nennt die Meldefristen 24 h / 72 h / 1 Monat"); + ok(nis2.includes("IM-C Test"), "NIS2-Vorlage trägt die meldende Organisation"); + + const dsgvo = buildDsgvoTemplate(tmpl); + ok(dsgvo.includes("Art. 33") && dsgvo.includes("72 h"), "DSGVO-Vorlage referenziert Art. 33 (72 h)"); + ok(dsgvo.includes("Kundendaten") && dsgvo.includes("Art. 34"), "DSGVO-Vorlage enthält betroffene Datenkategorien + Art.-34-Hinweis"); + + await cleanup(); + + if (failures) { + console.error(`\n✗ ${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(1); + } + console.log("\n✓ Alle IM-C-Verknüpfungs-/Export-Prüfungen bestanden."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/test-incidents.ts b/scripts/test-incidents.ts new file mode 100644 index 0000000..76c248a --- /dev/null +++ b/scripts/test-incidents.ts @@ -0,0 +1,153 @@ +// Akzeptanztest Modul „Vorfälle" (IM-A). +// +// Prüft: +// 1. Mandantenisolation: ein Vorfall aus Mandant A ist über dbForTenant(B) NICHT +// sichtbar (RLS/Guard) — und der Eigenzugriff funktioniert. +// 2. refNo-Format `INC--` + Fortlauf je Mandant/Jahr. +// 3. Statusübergang mit Pflichtfeld: nach „behoben"/„abgeschlossen" fehlen die +// Pflichtfelder → Übergang unzulässig; mit gesetzten Feldern → zulässig. +// 4. Vertraulichkeit: ein restricted-Vorfall wird nur für owner/manage sichtbar, +// für andere über den serverseitigen Filter ausgeblendet. +// +// Lauf: npx tsx scripts/test-incidents.ts (lokale isms-DB, .env im Repo). + +import "dotenv/config"; +import { prisma, dbForTenant } from "../src/server/db"; +import { nextIncidentRefNo } from "../src/server/incident-refno"; +import { canTransition, missingRequiredFields } from "../src/lib/incident"; +import { computeSeverity, impactFromCia } from "../src/lib/incident-severity"; +import type { Prisma } from "@prisma/client"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; +async function expectNull(fn: () => Promise, msg: string) { + const r = await fn(); + ok(r === null, `${msg}${r === null ? "" : ` — statt null: ${JSON.stringify(r)}`}`); +} + +const SLUG_A = "zz-inc-test-a"; +const SLUG_B = "zz-inc-test-b"; + +async function cleanup() { + const tenants = await prisma.tenant.findMany({ + where: { slug: { in: [SLUG_A, SLUG_B] } }, + select: { id: true }, + }); + const ids = tenants.map((t) => t.id); + if (ids.length) { + await prisma.incident.deleteMany({ where: { tenantId: { in: ids } } }); + await prisma.user.deleteMany({ where: { tenantId: { in: ids } } }); + await prisma.tenant.deleteMany({ where: { id: { in: ids } } }); + } + await prisma.identity.deleteMany({ where: { email: { in: ["zz-inc-owner@test.example", "zz-inc-other@test.example"] } } }); +} + +async function main() { + await cleanup(); + + const tenantA = await prisma.tenant.create({ data: { name: "INC-Test A", slug: SLUG_A } }); + const tenantB = await prisma.tenant.create({ data: { name: "INC-Test B", slug: SLUG_B } }); + + // Nutzer (owner + anderer) im Mandant A für die Vertraulichkeitsprüfung. + const idOwner = await prisma.identity.create({ data: { email: "zz-inc-owner@test.example", passwordHash: "x" } }); + const idOther = await prisma.identity.create({ data: { email: "zz-inc-other@test.example", passwordHash: "x" } }); + const owner = await prisma.user.create({ data: { tenantId: tenantA.id, identityId: idOwner.id, email: "zz-inc-owner@test.example", name: "Owner" } }); + const other = await prisma.user.create({ data: { tenantId: tenantA.id, identityId: idOther.id, email: "zz-inc-other@test.example", name: "Other" } }); + + const dbA = dbForTenant(tenantA.id); + const dbB = dbForTenant(tenantB.id); + + // ── 2. refNo-Format + Fortlauf ──────────────────────────────────────────── + const ref1 = await nextIncidentRefNo(prisma, tenantA.id); + ok(/^INC-\d{4}-\d{4}$/.test(ref1), `refNo-Format korrekt (${ref1})`); + const year = new Date().getFullYear(); + ok(ref1 === `INC-${year}-0001`, `erste refNo ist INC-${year}-0001 (${ref1})`); + + const incA1 = await dbA.incident.create({ + data: { tenantId: tenantA.id, refNo: ref1, title: "Vorfall A1", category: "phishing", severity: "mittel", status: "neu" }, + }); + const ref2 = await nextIncidentRefNo(prisma, tenantA.id); + ok(ref2 === `INC-${year}-0002`, `zweite refNo läuft fort → INC-${year}-0002 (${ref2})`); + await dbA.incident.create({ + data: { tenantId: tenantA.id, refNo: ref2, title: "Vorfall A2", category: "outage", severity: "niedrig", status: "neu" }, + }); + + // Mandant B startet unabhängig wieder bei 0001. + const refB1 = await nextIncidentRefNo(prisma, tenantB.id); + ok(refB1 === `INC-${year}-0001`, `Fortlauf ist mandantenlokal (B startet bei 0001: ${refB1})`); + const incB1 = await dbB.incident.create({ + data: { tenantId: tenantB.id, refNo: refB1, title: "Vorfall B1", category: "malware", severity: "hoch", status: "neu" }, + }); + + // ── 1. Mandantenisolation ───────────────────────────────────────────────── + const ownA = await dbA.incident.findFirst({ where: { id: incA1.id } }); + ok(ownA?.id === incA1.id, "Eigenzugriff: Mandant A sieht seinen Vorfall"); + await expectNull( + () => dbB.incident.findFirst({ where: { id: incA1.id } }), + "Isolation: Mandant B sieht den Vorfall von A NICHT (findFirst → null)", + ); + const bCount = await dbB.incident.count({ where: {} }); + ok(bCount === 1, `Isolation: Mandant B zählt nur seine eigenen Vorfälle (${bCount} === 1)`); + // Gegenrichtung + await expectNull( + () => dbA.incident.findFirst({ where: { id: incB1.id } }), + "Isolation: Mandant A sieht den Vorfall von B NICHT", + ); + + // ── 3. Statusübergang mit Pflichtfeld ───────────────────────────────────── + ok(canTransition("in_bearbeitung", "behoben"), "Übergang in_bearbeitung → behoben ist erlaubt"); + ok(!canTransition("neu", "abgeschlossen"), "Übergang neu → abgeschlossen ist NICHT erlaubt"); + + // ohne Pflichtfelder → fehlend gemeldet + const missBehoben = missingRequiredFields("behoben", { rootCause: null, resolution: "" }); + ok(missBehoben.includes("rootCause") && missBehoben.includes("resolution"), "behoben verlangt rootCause + resolution (fehlen erkannt)"); + const missClose = missingRequiredFields("abgeschlossen", { rootCause: "x", resolution: "y", closingNote: "", lessonsLearned: null }); + ok(missClose.includes("closingNote") && missClose.includes("lessonsLearned"), "abgeschlossen verlangt zusätzlich closingNote + lessonsLearned"); + // mit allen Feldern → nichts fehlt + const missOk = missingRequiredFields("abgeschlossen", { rootCause: "Ursache", resolution: "Lösung", closingNote: "Notiz", lessonsLearned: "LL" }); + ok(missOk.length === 0, "abgeschlossen mit allen Pflichtfeldern → zulässig (nichts fehlt)"); + + // Severity-Matrix (Default, §5) + ok(computeSeverity(impactFromCia(4, 0, 0), 4) === "kritisch", "Severity-Matrix: hohe Auswirkung + hohe Dringlichkeit → kritisch"); + ok(computeSeverity(impactFromCia(0, 0, 0), 0) === "niedrig", "Severity-Matrix: keine Auswirkung + keine Dringlichkeit → niedrig"); + + // ── 4. Vertraulichkeit (restricted) ─────────────────────────────────────── + const restricted = await dbA.incident.create({ + data: { tenantId: tenantA.id, refNo: await nextIncidentRefNo(prisma, tenantA.id), title: "Vertraulicher Vorfall", category: "unauthorized_access", severity: "hoch", status: "neu", restricted: true, ownerId: owner.id }, + }); + + // Filter wie in der Liste/Detail (page.tsx): manage/close sieht alles; sonst nur + // unrestricted + eigene (ownerId == userId). + const restrictedWhere = (canSee: boolean, userId: string): Prisma.IncidentWhereInput => + canSee ? {} : { OR: [{ restricted: false }, { ownerId: userId }] }; + + // manage/close → sichtbar + const seenByManager = await dbA.incident.findFirst({ where: { AND: [{ id: restricted.id }, restrictedWhere(true, other.id)] } }); + ok(seenByManager?.id === restricted.id, "restricted: Rolle mit manage/close sieht den vertraulichen Vorfall"); + // owner → sichtbar + const seenByOwner = await dbA.incident.findFirst({ where: { AND: [{ id: restricted.id }, restrictedWhere(false, owner.id)] } }); + ok(seenByOwner?.id === restricted.id, "restricted: der owner sieht seinen vertraulichen Vorfall"); + // anderer ohne manage/close → NICHT sichtbar + await expectNull( + () => dbA.incident.findFirst({ where: { AND: [{ id: restricted.id }, restrictedWhere(false, other.id)] } }), + "restricted: anderer Nutzer ohne manage/close sieht ihn NICHT", + ); + + await cleanup(); + + if (failures) { + console.error(`\n✗ ${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(1); + } + console.log("\n✓ Alle Incident-Prüfungen bestanden."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/scripts/test-invitation.ts b/scripts/test-invitation.ts new file mode 100644 index 0000000..cb737dc --- /dev/null +++ b/scripts/test-invitation.ts @@ -0,0 +1,103 @@ +// WS3-Abnahmetest (Option C) — Einladungs-Lifecycle. +// +// Anlage erfolgt ausschließlich per Einladung (goldene Regel 4): ein Einladungs- +// Token (TokenType "invitation", Prinzipal = Identity) führt auf /invite, wo der +// Eingeladene sein Erst-Passwort an der globalen Identity setzt. +// +// Geprüft: +// 1. checkInvitationToken erkennt einen gültigen Einladungs-Token. +// 2. redeemInvitation setzt das Passwort an der Identity; Login funktioniert sofort. +// 3. Token ist Single-use (zweite Einlösung scheitert). +// 4. Ein password_reset-Token wird vom Einladungs-Flow NICHT akzeptiert (Typ-Trennung). +// +// Lauf: npx tsx scripts/test-invitation.ts (setzt den Demo-Seed voraus) + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { hashPassword, verifyPassword } from "../src/server/password"; +import { issueToken, peekToken } from "../src/server/auth-token"; +import { checkInvitationToken, redeemInvitation } from "../src/server/actions/auth-recovery"; +import { authorizeTenantCredentials } from "../src/server/auth"; + +const EMAIL = "ws3-invite@demo.example"; +const NEW_PW = "Einladungs-Passwort-1!"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function cleanup() { + const identity = await prisma.identity.findUnique({ where: { email: EMAIL } }); + if (identity) await prisma.authToken.deleteMany({ where: { principalId: identity.id } }); + await prisma.user.deleteMany({ where: { email: EMAIL } }); + await prisma.identity.deleteMany({ where: { email: EMAIL } }); +} + +function form(token: string, pw: string): FormData { + const fd = new FormData(); + fd.set("token", token); + fd.set("password", pw); + fd.set("confirm", pw); + return fd; +} + +async function main() { + await cleanup(); + const demo = await prisma.tenant.findUniqueOrThrow({ where: { slug: "demo" } }); + const role = await prisma.role.findFirst({ where: { tenantId: demo.id, key: "user" } }); + + // Eingeladene, noch nicht aktivierte Person: Identity (Throwaway-Passwort) + Mitgliedschaft. + const identity = await prisma.identity.create({ + data: { email: EMAIL, passwordHash: await hashPassword("throwaway-xyz"), mustChangePassword: true, status: "ACTIVE" }, + }); + await prisma.user.create({ + data: { + tenantId: demo.id, identityId: identity.id, email: EMAIL, name: "WS3 Invite", + status: "ACTIVE", ...(role ? { userRoles: { create: [{ roleId: role.id }] } } : {}), + }, + }); + + console.log("\n— 1) Einladungs-Token wird erkannt —"); + const { raw } = await issueToken({ principalType: "identity", principalId: identity.id, tenantId: demo.id, type: "invitation" }); + ok(await checkInvitationToken(raw), "checkInvitationToken(raw) === true"); + + console.log("\n— 2) Einlösung setzt das Passwort an der Identity; Login funktioniert —"); + const done = await redeemInvitation({ status: "idle" }, form(raw, NEW_PW)); + ok(done.status === "done", `redeemInvitation → done (${done.status})`); + const after = await prisma.identity.findUniqueOrThrow({ where: { id: identity.id } }); + ok(await verifyPassword(after.passwordHash, NEW_PW), "Identity-Passwort ist das neu gesetzte"); + ok(after.mustChangePassword === false, "mustChangePassword zurückgesetzt"); + const login = await authorizeTenantCredentials({ email: EMAIL, password: NEW_PW, tenant: "demo" }); + ok(!!login && login.identityId === identity.id, "Login mit dem neuen Passwort erfolgreich"); + + console.log("\n— 3) Single-use —"); + ok((await peekToken(raw, "invitation")) === null, "Token nach Einlösung verbraucht"); + const second = await redeemInvitation({ status: "idle" }, form(raw, NEW_PW)); + ok(second.status === "error", "zweite Einlösung abgewiesen"); + + console.log("\n— 4) Typ-Trennung: password_reset ≠ invitation —"); + const reset = await issueToken({ principalType: "identity", principalId: identity.id, tenantId: demo.id, type: "password_reset" }); + ok((await checkInvitationToken(reset.raw)) === false, "Reset-Token wird vom Einladungs-Flow nicht akzeptiert"); + const wrongType = await redeemInvitation({ status: "idle" }, form(reset.raw, NEW_PW)); + ok(wrongType.status === "error", "redeemInvitation lehnt password_reset-Token ab"); + + await cleanup(); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-mail.ts b/scripts/test-mail.ts new file mode 100644 index 0000000..b406c6c --- /dev/null +++ b/scripts/test-mail.ts @@ -0,0 +1,146 @@ +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { enqueueMail } from "../src/server/mail/service"; +import { renderTemplate, TEMPLATE_KEYS, formatWhen } from "../src/server/mail/templates"; +import { getMailConfig, resetMailConfigCache } from "../src/server/mail/config"; +import { closeQueues, isQueueEnabled, isQueueReady } from "../src/server/mail/queue"; +import { closeMailProvider } from "../src/server/mail/provider-smtp"; + +/** + * SEC1 — Abnahmetest der Mail-Strecke (`npx tsx scripts/test-mail.ts`). + * + * Prüft ohne laufende App: + * 1. Alle Templates rendern in de und en, HTML **und** Text, mit Certvia- + * Branding und Dachmarken-Fußzeile. + * 2. Transaktionsmails tragen KEINEN Abmelde-Hinweis, Benachrichtigungen schon. + * 3. Ein echter Versand landet im lokalen SMTP (Mailhog/Mailpit) und das + * MailLog steht auf `sent` mit providerMessageId. + * 4. Idempotenz: derselbe dedupeKey erzeugt nur eine Mail. + * 5. Fehlende SMTP-Konfiguration führt zu `pending` + Begründung, nicht zu + * einem scheinbar erfolgreichen Versand. + * + * Voraussetzung für 3./4.: lokaler SMTP auf SMTP_HOST/SMTP_PORT + * (`docker compose up -d mailhog` → localhost:1025). + */ + +let failures = 0; +function check(name: string, ok: boolean, detail?: string) { + if (ok) { + console.log(` ✓ ${name}`); + } else { + failures++; + console.error(` ✗ ${name}${detail ? ` — ${detail}` : ""}`); + } +} + +const SAMPLE = { + invitation: { name: "Erika Muster", tenantName: "Muster GmbH", actionUrl: "https://example.test/a", expires: "morgen" }, + password_reset: { name: "Erika Muster", actionUrl: "https://example.test/r", expires: "in 60 Minuten" }, + password_changed: { name: "Erika Muster", when: "heute", ip: "203.0.113.7" }, + email_change_verify: { name: "Erika Muster", actionUrl: "https://example.test/v", expires: "in 60 Minuten", newEmail: "neu@example.test" }, + email_changed_notice: { name: "Erika Muster", newEmail: "neu@example.test", when: "heute" }, + mfa_changed: { name: "Erika Muster", change: "aktiviert", when: "heute" }, + notification: { name: "Erika Muster", subject: "Neue Aufgabe", body: "Text", actionUrl: "https://example.test/t", taskType: "policy_approval" }, + incident_notification: { name: "Erika Muster", subject: "Neuer Vorfall gemeldet", body: "Text", actionUrl: "https://example.test/i", refNo: "INC-2026-0042" }, + test: { name: "Erika Muster", when: "heute" }, +} as const; + +async function main() { + console.log("1) Template-Rendering (de/en, HTML + Text)"); + for (const key of TEMPLATE_KEYS) { + for (const locale of ["de", "en"] as const) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const r = renderTemplate(key, locale, SAMPLE[key] as any); + const ok = + r.subject.length > 0 && + r.html.includes("") && + r.html.includes("Certvia") && + r.html.includes("Ein Produkt von GEFIM") && + r.text.length > 0 && + !r.text.includes("<"); + check(`${key}/${locale}`, ok, `subject="${r.subject}"`); + } + } + + console.log("2) Abmelde-Hinweis nur bei Benachrichtigungen"); + const notif = renderTemplate("notification", "de", SAMPLE.notification); + const reset = renderTemplate("password_reset", "de", SAMPLE.password_reset); + check("notification trägt Präferenz-Hinweis", notif.text.includes("Einstellungen dazu")); + check("password_reset trägt KEINEN Abmelde-Hinweis", !reset.text.includes("Einstellungen dazu")); + + const { config } = getMailConfig(); + if (!config) { + console.log("3-4) übersprungen — keine SMTP-Konfiguration gesetzt."); + } else { + const mode = isQueueEnabled() && isQueueReady() ? "Queue (BullMQ)" : "inline"; + console.log(`3) Versand über ${config.host}:${config.port} — Modus: ${mode}`); + const key = `sec1-test:${process.pid}`; + const first = await enqueueMail({ + template: "test", + to: "sec1-abnahme@example.test", + tenantId: null, + locale: "de", + dedupeKey: key, + vars: { name: "Abnahme", when: formatWhen(new Date(), "de") }, + }); + check("Versand erfolgreich", first.status === "sent" || first.status === "queued", first.status); + + if ("mailLogId" in first) { + const row = await prisma.mailLog.findUnique({ where: { id: first.mailLogId } }); + check("MailLog-Status", row?.status === "sent" || row?.status === "pending", row?.status); + check("scope=platform bei tenantId=null", row?.scope === "platform"); + if (row?.status === "sent") { + check("providerMessageId gesetzt", Boolean(row.providerMessageId)); + check("keine Klartext-Secrets im Log", !JSON.stringify(row).includes("password")); + } + } + + console.log("4) Idempotenz"); + const second = await enqueueMail({ + template: "test", + to: "sec1-abnahme@example.test", + tenantId: null, + locale: "de", + dedupeKey: key, + vars: { name: "Abnahme", when: formatWhen(new Date(), "de") }, + }); + check("zweiter Aufruf mit gleichem dedupeKey → duplicate", second.status === "duplicate", second.status); + + // Aufräumen + if ("mailLogId" in first) { + await prisma.mailLog.delete({ where: { id: first.mailLogId } }).catch(() => {}); + } + } + + console.log("5) Fehlende SMTP-Konfiguration"); + const saved = process.env.SMTP_HOST; + delete process.env.SMTP_HOST; + resetMailConfigCache(); + const missing = getMailConfig(); + check("Konfiguration wird als unvollständig erkannt", missing.config === null); + check("Begründung vorhanden", Boolean(missing.reason?.includes("SMTP_HOST")), missing.reason); + if (saved) process.env.SMTP_HOST = saved; + resetMailConfigCache(); + + await cleanup(); + if (failures > 0) { + console.error(`\n✗ ${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(1); + } + console.log("\n✓ SEC1-Mailstrecke: alle Prüfungen bestanden."); + // Explizit beenden: offene Sockets (SMTP-Pool, Redis) halten sonst den + // Event-Loop offen, obwohl alle Prüfungen durch sind. + process.exit(0); +} + +async function cleanup() { + await prisma.$disconnect(); + await closeMailProvider(); + await closeQueues(); +} + +main().catch(async (err) => { + console.error(err); + await cleanup(); + process.exit(1); +}); diff --git a/scripts/test-maturity.ts b/scripts/test-maturity.ts new file mode 100644 index 0000000..ed7a3e4 --- /dev/null +++ b/scripts/test-maturity.ts @@ -0,0 +1,98 @@ +// Unit-Tests (Story A7-2) für die Reifegrad-Engine gegen die C5-Regelbeispiele. +// Lauf: npx tsx scripts/test-maturity.ts +import { + suggestMaturity, + targetMaturity, + openPoints, + specForControl, + type ControlEvidence, +} from "../src/lib/maturity"; + +let failed = 0; +function check(name: string, cond: boolean, detail = "") { + if (cond) console.log(` ok ${name}`); + else { + failed++; + console.error(`FAIL ${name}${detail ? ` — ${detail}` : ""}`); + } +} + +const base: ControlEvidence = { + policy: "fehlt", + verfahren: "fehlt", + assetLinked: false, + riskLinked: false, + operationalProof: false, +}; + +// Control mit Richtlinie + Verfahren + Asset (1.3.1: R02 / VA-08 / (A)). +const s131 = specForControl("1.3.1"); +check("1.3.1 hat Verfahren + needsAsset", s131.verfahren.length === 1 && s131.needsAsset); + +console.log("§2 Belegkonstellationen (Control 1.3.1):"); +check("R0 — keine Belege → 0", suggestMaturity(s131, base).value === 0); +check("R1a — Richtlinie verknüpft, unvalidiert → 1", suggestMaturity(s131, { ...base, policy: "verknuepft" }).rule === "R1a"); +check( + "R1b — Richtlinie validiert, Verfahren fehlt → 1", + suggestMaturity(s131, { ...base, policy: "validiert" }).rule === "R1b", +); +check( + "R1c — nur operativer Nachweis, keine validierte Richtlinie → 1", + suggestMaturity(s131, { ...base, operationalProof: true }).rule === "R1c", +); +check( + "R2 — Richtlinie+Verfahren validiert + Asset, kein Nachweis → 2", + suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true }).value === 2, +); +check( + "R2 verweigert bei fehlender Asset-Verknüpfung → 1", + suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: false }).value === 1, +); +check( + "R3 — R2 + aktueller Wirksamkeitsnachweis → 3", + suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true }).value === 3, +); +check( + "Deckelung — Widerspruch/Findings → max. 1 (CAP)", + suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true, contradiction: true }).value === 1, +); + +// Control ohne Verfahren (1.1.1: L00 / — / …): Grad 2 über validierte Umsetzungsregelung (N-basisch). +console.log("§2 Sonderfall ohne Verfahren (Control 1.1.1):"); +const s111 = specForControl("1.1.1"); +check("1.1.1 ohne Verfahren", s111.verfahren.length === 0); +check( + "R2 ohne V — Richtlinie validiert + validierte Umsetzungsregelung → 2", + suggestMaturity(s111, { ...base, policy: "validiert", implementationRule: true }).value === 2, +); +check( + "R1b ohne V — Richtlinie validiert, keine Umsetzungsregelung → 1", + suggestMaturity(s111, { ...base, policy: "validiert" }).value === 1, +); +check( + "R3 ohne V — Umsetzungsregelung + aktueller Wirksamkeitsnachweis → 3", + suggestMaturity(s111, { ...base, policy: "validiert", implementationRule: true, operationalProof: true }).value === 3, +); + +// Zielreifegrad (§3). +console.log("§3 Zielreifegrad:"); +check("AL3 → 3", targetMaturity({ level: "AL3", flags: {} }) === 3); +check("AL2 reiner MUSS-Scope → 2", targetMaturity({ level: "AL2", flags: {} }) === 2); +check("AL2 + SOLL → 3", targetMaturity({ level: "AL2", flags: { FLAG_INCLUDE_SHOULD: true } }) === 3); +check("AL2 + HOCH → 3", targetMaturity({ level: "AL2", flags: { FLAG_HIGH_PROTECTION: true } }) === 3); + +// Offene Punkte (§4). +console.log("§4 Offene Punkte:"); +const evGap: ControlEvidence = { ...base, policy: "validiert", verfahren: "fehlt", assetLinked: false }; +const sugGap = suggestMaturity(s131, evGap); +const ops = openPoints(s131, evGap, sugGap, 3); +check("Verfahren-Gap erzeugt Punkt", ops.some((o) => o.kind === "verfahren")); +check("Asset-Verknüpfungs-Gap erzeugt Punkt", ops.some((o) => o.kind === "verknuepfung")); +check("Nachweis-Gap bei Ziel 3 erzeugt Punkt", ops.some((o) => o.kind === "nachweis")); +check( + "kein Gap bei erfülltem Ziel", + openPoints(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true }, suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true }), 3).length === 0, +); + +console.log(failed === 0 ? "\nAlle Reifegrad-Tests grün." : `\n${failed} Test(s) fehlgeschlagen.`); +process.exit(failed === 0 ? 0 : 1); diff --git a/scripts/test-mfa-hardening.ts b/scripts/test-mfa-hardening.ts new file mode 100644 index 0000000..329d31c --- /dev/null +++ b/scripts/test-mfa-hardening.ts @@ -0,0 +1,106 @@ +// Korrektheitsnachweis für F-17: MFA-Härtung (Krypto + TOTP-Replay-Schutz). +// +// Drei Nachweise (jeweils Assertion; am Ende "OK" oder Exit-Code != 0): +// (1) Recovery-Codes: ein generierter Code verifiziert korrekt gegen seinen +// Argon2id-Hash (matchRecovery findet ihn), ein falscher Code nicht. +// Zusatz: der Kompatibilitätspfad akzeptiert einen Bestands-Hash im +// SHA-256-Format weiterhin. +// (2) Entropie/Format: 4er-Gruppierung, 20 Hex-Zeichen normalisiert = 80 Bit +// Entropie (>= 64 Bit gefordert), Hashes sind Argon2id ($argon2id$). +// (3) TOTP-Replay: derselbe Code/Zeitschritt wird beim zweiten Mal (mit +// afterStep = lastTotpStep) abgelehnt; ein älterer Zeitschritt lässt den +// aktuellen Code weiterhin zu. +// +// Lauf: npx tsx scripts/test-mfa-hardening.ts (reine Krypto-/TOTP-Logik, keine DB). + +import "dotenv/config"; +import { createHash } from "node:crypto"; +import { generateSync } from "otplib"; +import { + generateRecoveryCodes, + matchRecovery, + hashRecovery, + verifyTotp, + newTotpSecret, +} from "@/server/mfa"; + +function assert(cond: unknown, msg: string): asserts cond { + if (!cond) { + console.error(`FEHLGESCHLAGEN: ${msg}`); + process.exit(1); + } + console.log(` ok: ${msg}`); +} + +async function main() { + // ── (1) Recovery-Codes: Argon2id-Verifikation korrekt/ falsch ──────────── + console.log("\n(1) Recovery-Codes gegen Argon2id-Hashes:"); + const { plain, hashed } = await generateRecoveryCodes(10); + + assert(plain.length === 10 && hashed.length === 10, "10 Codes + 10 Hashes erzeugt"); + assert( + hashed.every((h) => h.startsWith("$argon2id$")), + "alle Hashes sind Argon2id ($argon2id$)", + ); + + // Ein echter Code (mit und ohne Gruppierungs-Bindestriche) wird gefunden. + const idx = await matchRecovery(plain[3], hashed); + assert(idx === 3, "korrekter Recovery-Code wird am richtigen Index gefunden"); + const idxNormalized = await matchRecovery(plain[3].replace(/-/g, "").toUpperCase(), hashed); + assert(idxNormalized === 3, "Code wird normalisiert erkannt (ohne Bindestriche, Großschreibung)"); + + // Ein falscher Code wird abgelehnt. + const idxWrong = await matchRecovery("0000-0000-0000-0000", hashed); + assert(idxWrong === -1, "falscher Recovery-Code wird abgelehnt (-1)"); + + // Kompatibilitätspfad: ein Bestands-Hash im SHA-256-Format wird weiter akzeptiert. + const legacyPlain = "abcd-1234-ef56"; + const legacySha = createHash("sha256").update(legacyPlain.replace(/[\s-]/g, "").toLowerCase()).digest("hex"); + const legacyIdx = await matchRecovery(legacyPlain, [legacySha]); + assert(legacyIdx === 0, "Bestands-Hash (SHA-256, 64 Hex) wird übergangsweise akzeptiert"); + const legacyWrong = await matchRecovery("ffff-ffff-ffff", [legacySha]); + assert(legacyWrong === -1, "falscher Code gegen SHA-256-Bestandshash wird abgelehnt"); + + // ── (2) Entropie / Format ──────────────────────────────────────────────── + console.log("\n(2) Entropie und Format:"); + const groupFormat = /^[0-9a-f]{5}-[0-9a-f]{5}-[0-9a-f]{5}-[0-9a-f]{5}$/; + assert(plain.every((c) => groupFormat.test(c)), "Format 5-5-5-5 Hex mit Gruppierung"); + const normalizedLen = plain[0].replace(/-/g, "").length; + assert(normalizedLen === 20, "20 Hex-Zeichen normalisiert (= 80 Bit Entropie, >= 64 gefordert)"); + const bits = normalizedLen * 4; + assert(bits >= 64, `Entropie ${bits} Bit >= 64 Bit`); + // hashRecovery liefert einen frischen Argon2id-Hash (Salt → zwei Hashes verschieden). + const h1 = await hashRecovery(plain[0]); + const h2 = await hashRecovery(plain[0]); + assert(h1.startsWith("$argon2id$") && h2.startsWith("$argon2id$"), "hashRecovery liefert Argon2id"); + assert(h1 !== h2, "gesalzen: zwei Hashes desselben Codes unterscheiden sich"); + + // ── (3) TOTP-Replay-Schutz ──────────────────────────────────────────────── + console.log("\n(3) TOTP-Replay-Schutz:"); + const secret = newTotpSecret(); + const token = generateSync({ secret }); // Code für den aktuellen Zeitschritt + + const first = verifyTotp(token, secret); + assert(first.ok, "TOTP-Code verifiziert im aktuellen Zeitfenster"); + const step = first.ok ? first.step : -1; + console.log(` (akzeptierter Zeitschritt: ${step})`); + + // Zweite Verwendung mit lastTotpStep = step → Replay wird abgelehnt. + const replay = verifyTotp(token, secret, step); + assert(!replay.ok, "derselbe Code/Zeitschritt wird beim zweiten Mal abgelehnt (Replay)"); + + // Ein älterer lastTotpStep (step - 1) lehnt den aktuellen Code NICHT ab. + const older = verifyTotp(token, secret, step - 1); + assert(older.ok && (older.ok ? older.step : -1) === step, "älterer Zeitschritt lässt den aktuellen Code zu"); + + // Ein offensichtlich falscher Code ist immer ungültig. + const bad = verifyTotp("000000", secret); + assert(!bad.ok, "falscher 6-stelliger Code wird abgelehnt"); + + console.log("\nOK — alle F-17-Nachweise bestanden."); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/scripts/test-password-pepper.ts b/scripts/test-password-pepper.ts new file mode 100644 index 0000000..955514d --- /dev/null +++ b/scripts/test-password-pepper.ts @@ -0,0 +1,59 @@ +// Härtung §1 — Pepper-Abnahmetest. +// +// Weist nach, dass der PASSWORD_PEPPER tatsächlich in Argon2-Hash UND -Verify eingeht: +// 1. hashPassword+verifyPassword (beide peppered) → true. +// 2. Verify OHNE Pepper (roher argon2) gegen einen peppered Hash → false. +// 3. Verify mit FALSCHEM Pepper → false. +// 4. Falsches Passwort mit korrektem Pepper → false. +// 5. Recovery-Codes (mfa.ts nutzt hashPassword/verifyPassword) matchen mit Pepper. +// +// Lauf: npx tsx scripts/test-password-pepper.ts (PASSWORD_PEPPER muss gesetzt sein) + +import "dotenv/config"; +import { verify as rawVerify } from "@node-rs/argon2"; +import { hashPassword, verifyPassword } from "../src/server/password"; +import { generateRecoveryCodes, matchRecovery } from "../src/server/mfa"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const PW = "Pepper-Test-Passwort-1!"; + +async function main() { + ok(/^[0-9a-fA-F]{64}$/.test(process.env.PASSWORD_PEPPER ?? ""), "PASSWORD_PEPPER ist gesetzt (32-Byte hex)"); + + const h = await hashPassword(PW); + + console.log("\n— 1) korrekter Pepper —"); + ok(await verifyPassword(h, PW), "verifyPassword mit korrektem Pepper → true"); + + console.log("\n— 2/3) fehlender / falscher Pepper —"); + ok((await rawVerify(h, PW).catch(() => false)) === false, "verify OHNE Pepper → false (Pepper geht wirklich in den Hash)"); + const wrongPepper = Buffer.alloc(32, 0x11); + ok((await rawVerify(h, PW, { secret: wrongPepper }).catch(() => false)) === false, "verify mit FALSCHEM Pepper → false"); + + console.log("\n— 4) falsches Passwort —"); + ok((await verifyPassword(h, "falsch!!")) === false, "falsches Passwort (korrekter Pepper) → false"); + + console.log("\n— 5) Recovery-Codes mit Pepper —"); + const { plain, hashed } = await generateRecoveryCodes(3); + ok((await matchRecovery(plain[0]!, hashed)) === 0, "gültiger Recovery-Code matcht (peppered hash/verify)"); + ok((await matchRecovery("000-000", hashed)) === -1, "ungültiger Recovery-Code matcht nicht"); +} + +main() + .then(() => { + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + process.exit(0); + }) + .catch((e) => { + console.error(e); + process.exit(1); + }); diff --git a/scripts/test-readiness.ts b/scripts/test-readiness.ts new file mode 100644 index 0000000..f5e7049 --- /dev/null +++ b/scripts/test-readiness.ts @@ -0,0 +1,56 @@ +// Akzeptanztest der Readiness-Logik (Story B7-1, C9 §1/§2). Reine Logik, kein DB-Zugriff. +// Lauf: npx tsx scripts/test-readiness.ts (Exit 1 bei Fehler). + +import { interpretationBand, averageReifegrad, buildNextSteps, computeReadiness, type ControlAssessment } from "../src/lib/readiness"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +// — C9 §1: Textbänder je Ø-Reifegrad — +ok(interpretationBand(0).band === "Aufbau", "Ø 0 → Aufbau"); +ok(interpretationBand(1.49).band === "Aufbau", "Ø 1,49 → Aufbau"); +ok(interpretationBand(1.5).band === "Etabliert im Aufbau", "Ø 1,5 → Etabliert im Aufbau"); +ok(interpretationBand(2.49).band === "Etabliert im Aufbau", "Ø 2,49 → Etabliert im Aufbau"); +ok(interpretationBand(2.5).band === "Assessment-nah", "Ø 2,5 → Assessment-nah"); +ok(interpretationBand(2.99).band === "Assessment-nah", "Ø 2,99 → Assessment-nah"); +ok(interpretationBand(3.0).band === "Assessment-reif", "Ø 3,0 → Assessment-reif"); + +// — Ø-Reifegrad: „unbestätigt zählt nicht als erfüllt" (geht mit 0 ein) — +{ + const a: ControlAssessment[] = [ + { control: "1.1.1", chapter: "1", reifegrad: 3, bestaetigt: true }, + { control: "1.1.2", chapter: "1", reifegrad: 3, bestaetigt: false }, // zählt als 0 + ]; + ok(averageReifegrad(a) === 1.5, "unbestätigt zählt als 0 → Ø(3,0) = 1,5"); + ok(averageReifegrad([]) === null, "keine Assessments → null (A7 ausstehend)"); +} + +// — C9 §2: dynamische nächste Schritte — +{ + const all = buildNextSteps({ openHighCount: 2, unvalidatedCount: 5, prototypeGap: true, evidenceUploadPending: true }); + ok(all.some((s) => s.includes("2 Hoch-Punkte")), "Hoch-Punkte → Schritt mit Anzahl"); + ok(all.some((s) => s.includes("5 Objekte")), "unvalidierte Objekte → Schritt mit Anzahl"); + ok(all.some((s) => s.includes("Prototypen")), "Prototyp-Gap → Prototyp-Schritt"); + ok(all.length === 4, "alle vier Regeln greifen"); + const none = buildNextSteps({ openHighCount: 0, unvalidatedCount: 0, prototypeGap: false, evidenceUploadPending: false }); + ok(none.length === 0, "keine Bedingung → keine Schritte"); +} + +// — computeReadiness: assessmentPending ohne A7-Daten — +{ + const r = computeReadiness({ + assessments: [], bestaetigtAnteil: 0, + offenJePrioritaet: { hoch: 1, mittel: 2, niedrig: 0 }, + pruefzielAbdeckung: [{ pruefziel: "informationssicherheit", anforderungen: 300 }], + zielReifegrad: 3, + nextSteps: { openHighCount: 1, unvalidatedCount: 0, prototypeGap: false, evidenceUploadPending: false }, + }); + ok(r.assessmentPending === true && r.avgReifegrad === null && r.band === null, "ohne Assessments → pending, kein Reifegrad/Band"); + ok(r.nextSteps.length === 1, "Kennzahlen-basierte Schritte trotzdem berechnet"); +} + +console.log(failures === 0 ? "\nOK — alle Readiness-Tests grün" : `\nPRUEFEN — ${failures} Fehler`); +process.exit(failures === 0 ? 0 : 1); diff --git a/scripts/test-reimport.ts b/scripts/test-reimport.ts new file mode 100644 index 0000000..46aef0e --- /dev/null +++ b/scripts/test-reimport.ts @@ -0,0 +1,88 @@ +import "dotenv/config"; +import { join } from "node:path"; +import { prisma } from "../src/server/db"; +import { importPolicies } from "../prisma/import-policies"; + +const SEED_DIR = join(process.cwd(), "seed", "isms-vorlagenpaket-v2"); +const ok = (c: boolean, m: string) => console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); + +async function main() { + const tenant = await prisma.tenant.findFirst({ where: { slug: "demo" } }); + if (!tenant) throw new Error("Demo-Mandant fehlt"); + const t = tenant.id; + + // Ausgangszustand eines echten Dokuments + einer Variable sichern + const doc0 = await prisma.policyDocument.findFirst({ where: { tenantId: t, code: "R08" } }); + const varName = "ORG_NAME"; + const var0 = await prisma.policyVariable.findFirst({ where: { tenantId: t, key: varName } }); + if (!doc0 || !var0) throw new Error("Erwartetes Dokument R08 / Variable ORG_NAME fehlt"); + + // 1) Kuratierten Zustand simulieren: Freigabe-Status, TISAX-Override, Einreicher, + // geänderter Titel (Inhalts-Diff) + nutzergepflegter Variablenwert. + await prisma.policyDocument.update({ + where: { id: doc0.id }, + data: { status: "ENTWURF", protectionOverride: "AL3", submittedBy: "tester", title: "MANUELL GEÄNDERTER TITEL" }, + }); + await prisma.policyVariable.update({ where: { id: var0.id }, data: { value: "Mustermann Spezial GmbH" } }); + + // 2) Entfernte Anforderung simulieren (nicht im Paket): muss deaktiviert, nicht gelöscht werden. + const fakeReqId = "ZZ-REMOVED-TEST-1"; + await prisma.policyRequirement.deleteMany({ where: { tenantId: t, reqId: fakeReqId } }); + await prisma.policyRequirement.create({ + data: { tenantId: t, reqId: fakeReqId, policyCode: "R08", control: "0.0.0", obligation: "MUSS", requirement: "Test", implementation: "" }, + }); + + // 3) Dry-Run: Vorschau ohne Schreibzugriff + const preview = await importPolicies(prisma, t, SEED_DIR, { dryRun: true }); + console.log("\n— Dry-Run-Report —"); + console.log(JSON.stringify(preview.report, null, 0)); + ok(preview.report.documents.updated >= 1, "Dry-Run erkennt Titeländerung an R08 (updated ≥ 1)"); + ok(preview.report.documents.archived === 0, "Dry-Run deaktiviert KEINE verwalteten Register (CRYPTO/HANDBUCH/…)"); + ok(preview.report.requirements.archived === 1, "Dry-Run erkennt 1 zu deaktivierende Anforderung"); + const stillDraftAfterDry = await prisma.policyDocument.findUnique({ where: { id: doc0.id } }); + ok(stillDraftAfterDry?.title === "MANUELL GEÄNDERTER TITEL", "Dry-Run schreibt NICHT (Titel unverändert)"); + + // 4) Echter Re-Import + const run1 = await importPolicies(prisma, t, SEED_DIR, { dryRun: false, actorId: null }); + console.log("\n— Re-Import-Report —"); + console.log(JSON.stringify(run1.report, null, 0)); + + const docA = await prisma.policyDocument.findUnique({ where: { id: doc0.id } }); + ok(docA?.status === "ENTWURF", "Freigabe-Status bleibt erhalten (ENTWURF)"); + ok(docA?.protectionOverride === "AL3", "TISAX-Override bleibt erhalten (AL3)"); + ok(docA?.submittedBy === "tester", "Einreicher (Freigabe-Workflow) bleibt erhalten"); + ok(docA?.title === doc0.title, "Titel wurde aus dem Paket aktualisiert (Inhalt)"); + ok(docA?.archivedAt === null, "Dokument bleibt aktiv"); + + const varA = await prisma.policyVariable.findUnique({ where: { id: var0.id } }); + ok(varA?.value === "Mustermann Spezial GmbH", "Nutzergepflegter Variablenwert bleibt erhalten"); + + const fakeA = await prisma.policyRequirement.findFirst({ where: { tenantId: t, reqId: fakeReqId } }); + ok(!!fakeA && fakeA.archivedAt !== null, "Entfernte Anforderung ist deaktiviert (archivedAt gesetzt), NICHT gelöscht"); + + const auditA = await prisma.auditLog.findFirst({ where: { tenantId: t, entity: "policy_package" }, orderBy: { createdAt: "desc" } }); + ok(!!auditA, "Änderungsreport im Audit-Log protokolliert"); + + // 5) Idempotenz: zweiter Lauf ohne externe Änderung → keine Diffs + const run2 = await importPolicies(prisma, t, SEED_DIR, { dryRun: false }); + const r = run2.report; + const noChanges = + r.documents.added + r.documents.updated + r.documents.archived + r.documents.reactivated === 0 && + r.requirements.added + r.requirements.updated + r.requirements.archived + r.requirements.reactivated === 0 && + r.variables.added + r.variables.updated === 0 && r.baseline.added + r.baseline.updated === 0 && + r.evidence.added + r.evidence.updated === 0; + console.log("\n— Idempotenz-Report —"); + console.log(JSON.stringify(r, null, 0)); + ok(noChanges, "Zweiter Lauf ist idempotent (keine added/updated/archived/reactivated)"); + + // Aufräumen: Testartefakt entfernen, kuratierten Zustand zurücksetzen + await prisma.policyRequirement.deleteMany({ where: { tenantId: t, reqId: fakeReqId } }); + await prisma.policyDocument.update({ + where: { id: doc0.id }, + data: { status: doc0.status, protectionOverride: doc0.protectionOverride, submittedBy: doc0.submittedBy, title: doc0.title, archivedAt: null }, + }); + await prisma.policyVariable.update({ where: { id: var0.id }, data: { value: var0.value } }); + console.log("\n✓ aufgeräumt (Testartefakte entfernt, R08/ORG_NAME zurückgesetzt)"); +} + +main().then(() => process.exit(0)).catch((e) => { console.error(e); process.exit(1); }); diff --git a/scripts/test-reset-flow.ts b/scripts/test-reset-flow.ts new file mode 100644 index 0000000..c31736d --- /dev/null +++ b/scripts/test-reset-flow.ts @@ -0,0 +1,203 @@ +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { hashPassword, verifyPassword } from "../src/server/password"; +import { redeemPasswordReset, requestPasswordReset } from "../src/server/actions/auth-recovery"; +import { issueToken, peekToken } from "../src/server/auth-token"; +import { resetRateLimits } from "../src/server/rate-limit"; +import { closeQueues } from "../src/server/mail/queue"; +import { closeMailProvider } from "../src/server/mail/provider-smtp"; + +/** + * SEC2 — End-to-End des Reset-Ablaufs gegen ein Wegwerf-Konto + * (`npx tsx scripts/test-reset-flow.ts`). + * + * Ergänzt `test-auth-selfservice.ts` (dort: die Token-/Limit-Eigenschaften + * isoliert) um das Zusammenspiel: Anfrage → Token → Einlösung → Passwort + * geschrieben → Sessions entwertet → Bestätigungsmail → Audit. + * + * Zusätzlich die beiden Fälle, die man leicht falsch baut: + * - ein **Policy-Verstoß darf den Link nicht entwerten** (sonst ist der Nutzer + * nach einem Tippfehler ausgesperrt), + * - ein **deaktiviertes Konto** bekommt keinen Reset, aber dieselbe Antwort. + * + * Das Testkonto wird angelegt und am Ende restlos entfernt. + */ + +const EMAIL = "sec2-e2e@example.test"; +const OLD_PW = "Sec2-E2E-Alt-2026!"; +const NEW_PW = "Sec2-E2E-Neu-2026!"; + +let failures = 0; +function check(name: string, ok: boolean, detail?: string) { + if (ok) console.log(` ✓ ${name}`); + else { + failures++; + console.error(` ✗ ${name}${detail ? ` — ${detail}` : ""}`); + } +} + +async function main() { + resetRateLimits(); + + const tenant = await prisma.tenant.findFirst({ where: { status: "ACTIVE" } }); + if (!tenant) throw new Error("Kein aktiver Mandant vorhanden — bitte zuerst seeden."); + + await prisma.user.deleteMany({ where: { email: EMAIL } }); + await prisma.identity.deleteMany({ where: { email: EMAIL, memberships: { none: {} } } }); + // Option C: Mitgliedschaft braucht eine globale Identity (Anmeldung). + const identity = await prisma.identity.create({ data: { email: EMAIL, passwordHash: await hashPassword(OLD_PW) } }); + const user = await prisma.user.create({ + data: { + tenantId: tenant.id, + identityId: identity.id, + email: EMAIL, + name: "SEC2 E2E", + status: "ACTIVE", + }, + }); + + try { + console.log("1) Anfrage"); + const fd = new FormData(); + fd.set("email", EMAIL); + fd.set("domain", "tenant"); + const req = await requestPasswordReset({ status: "idle" }, fd); + check("neutrale Antwort", req.status === "done"); + + const unknownEmail = `unbekannt-${Date.now()}@example.test`; + const fdUnknown = new FormData(); + fdUnknown.set("email", unknownEmail); + fdUnknown.set("domain", "tenant"); + const reqUnknown = await requestPasswordReset({ status: "idle" }, fdUnknown); + check("unbekannte Adresse: identische Antwort", JSON.stringify(req) === JSON.stringify(reqUnknown)); + check( + "keine Mail an die unbekannte Adresse", + (await prisma.mailLog.count({ where: { to: unknownEmail } })) === 0, + ); + check( + "Token nur für das existierende Konto (Prinzipal = Identity)", + (await prisma.authToken.count({ where: { principalId: identity.id, usedAt: null } })) === 1, + ); + const resetMail = await prisma.mailLog.findFirst({ + where: { to: EMAIL, template: "password_reset" }, + }); + check("Reset-Mail eingestellt", resetMail != null, resetMail?.status); + + // Das Rohtoken existiert nur im Link. Für den weiteren Ablauf einen frischen + // Link ausstellen — die Neuanforderung entwertet den vorherigen (geprüft in + // test-auth-selfservice.ts). + const issued = await issueToken({ + principalType: "identity", + principalId: identity.id, + tenantId: tenant.id, + type: "password_reset", + }); + + console.log("2) Policy-Verstoß entwertet den Link nicht"); + const weak = new FormData(); + weak.set("token", issued.raw); + weak.set("domain", "tenant"); + weak.set("password", "kurz"); + weak.set("confirm", "kurz"); + check("schwaches Passwort abgelehnt", (await redeemPasswordReset({ status: "idle" }, weak)).status === "error"); + check("Link danach noch gültig", (await peekToken(issued.raw, "password_reset")) != null); + + const mismatch = new FormData(); + mismatch.set("token", issued.raw); + mismatch.set("domain", "tenant"); + mismatch.set("password", NEW_PW); + mismatch.set("confirm", `${NEW_PW}x`); + check( + "abweichende Wiederholung abgelehnt", + (await redeemPasswordReset({ status: "idle" }, mismatch)).status === "error", + ); + check("Link weiterhin gültig", (await peekToken(issued.raw, "password_reset")) != null); + + console.log("3) Einlösung (Passwort/Session an der Identity)"); + const before = await prisma.identity.findUniqueOrThrow({ where: { id: identity.id } }); + const fd2 = new FormData(); + fd2.set("token", issued.raw); + fd2.set("domain", "tenant"); + fd2.set("password", NEW_PW); + fd2.set("confirm", NEW_PW); + const done = await redeemPasswordReset({ status: "idle" }, fd2); + check("Einlösung erfolgreich", done.status === "done", JSON.stringify(done)); + + const after = await prisma.identity.findUniqueOrThrow({ where: { id: identity.id } }); + check("Passwort-Hash (Identity) geändert", before.passwordHash !== after.passwordHash); + check("neues Passwort gültig", await verifyPassword(after.passwordHash, NEW_PW)); + check("altes Passwort ungültig", !(await verifyPassword(after.passwordHash, OLD_PW))); + check("Sessions invalidiert (Identity)", after.sessionsValidAfter != null); + check("Force-Change zurückgesetzt (Identity)", after.mustChangePassword === false); + check("Link verbraucht", (await peekToken(issued.raw, "password_reset")) === null); + + const secondUse = new FormData(); + secondUse.set("token", issued.raw); + secondUse.set("domain", "tenant"); + secondUse.set("password", NEW_PW); + secondUse.set("confirm", NEW_PW); + check( + "zweite Einlösung abgewiesen", + (await redeemPasswordReset({ status: "idle" }, secondUse)).status === "error", + ); + + const confirmMail = await prisma.mailLog.findFirst({ + where: { to: EMAIL, template: "password_changed" }, + }); + check("Bestätigungsmail versendet", confirmMail != null, confirmMail?.status); + + const audit = await prisma.auditLog.findFirst({ + where: { entity: "password_reset", entityId: identity.id }, + }); + check("Audit-Eintrag vorhanden", audit != null); + check( + "kein Token im Audit", + audit == null || !JSON.stringify(audit).includes(issued.raw.slice(0, 12)), + ); + check( + "kein Token im MailLog", + (await prisma.mailLog.count({ where: { dedupeKey: { contains: issued.raw.slice(0, 12) } } })) === 0, + ); + + console.log("4) Deaktivierte Identity"); + // Option C: das Konto ist die Identity — Deaktivierung wirkt an ihr, nicht an + // der einzelnen Mitgliedschaft. + await prisma.identity.update({ where: { id: identity.id }, data: { status: "DISABLED" } }); + resetRateLimits(); + const openBefore = await prisma.authToken.count({ + where: { principalId: identity.id, type: "password_reset", usedAt: null }, + }); + const fd3 = new FormData(); + fd3.set("email", EMAIL); + fd3.set("domain", "tenant"); + const req3 = await requestPasswordReset({ status: "idle" }, fd3); + const openAfter = await prisma.authToken.count({ + where: { principalId: identity.id, type: "password_reset", usedAt: null }, + }); + check("Antwort trotzdem neutral", req3.status === "done"); + check("kein neuer Token", openAfter === openBefore); + } finally { + await prisma.authToken.deleteMany({ where: { principalId: { in: [identity.id, user.id] } } }); + await prisma.mailLog.deleteMany({ where: { to: EMAIL } }); + await prisma.auditLog.deleteMany({ where: { actorId: { in: [identity.id, user.id] } } }); + await prisma.user.delete({ where: { id: user.id } }).catch(() => {}); + await prisma.identity.deleteMany({ where: { email: EMAIL } }); + } + + await prisma.$disconnect(); + await closeMailProvider(); + await closeQueues(); + + if (failures > 0) { + console.error(`\n✗ ${failures} Prüfung(en) fehlgeschlagen.`); + process.exit(1); + } + console.log("\n✓ SEC2 Reset-Ablauf: alle Prüfungen bestanden."); + process.exit(0); +} + +main().catch(async (err) => { + console.error(err); + await prisma.$disconnect().catch(() => {}); + process.exit(1); +}); diff --git a/scripts/test-review.ts b/scripts/test-review.ts new file mode 100644 index 0000000..5136182 --- /dev/null +++ b/scripts/test-review.ts @@ -0,0 +1,78 @@ +// AP4 — Managementklauseln (9.1 Kennzahlen, 9.3 Managementbewertung, 10.2 CAPA). +// Prüft Datenmodell, Relationen und Kern-Invarianten der DoD gegen die lokale DB +// (Wegwerf-Mandant, dbForTenant → RLS-Pfad). +// +// Lauf: npx tsx scripts/test-review.ts + +import "dotenv/config"; +import { prisma, dbForTenant } from "../src/server/db"; + +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; +const SLUG = "ap4-test-review"; + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG }, select: { id: true } }); + if (!t) return; + const id = t.id; + await prisma.correctiveAction.deleteMany({ where: { tenantId: id } }); + await prisma.nonconformity.deleteMany({ where: { tenantId: id } }); + await prisma.managementReviewDecision.deleteMany({ where: { tenantId: id } }); + await prisma.managementReview.deleteMany({ where: { tenantId: id } }); + await prisma.kpiValue.deleteMany({ where: { tenantId: id } }); + await prisma.kpi.deleteMany({ where: { tenantId: id } }); + await prisma.tenant.delete({ where: { id } }); +} + +async function main() { + await cleanup(); + const tenant = await prisma.tenant.create({ data: { name: "AP4", slug: SLUG } }); + const t = tenant.id; + const db = dbForTenant(t); + + // ── 9.1 Kennzahl über zwei Perioden auswertbar ────────────────────────────── + const kpi = await db.kpi.create({ data: { tenantId: t, name: "Überfällige Maßnahmen", target: "< 5%", unit: "%", cadence: "quartalsweise" }, select: { id: true } }); + for (const [period, value] of [["2026-Q1", "8%"], ["2026-Q2", "4%"]]) { + await db.kpiValue.upsert({ + where: { tenantId_kpiId_period: { tenantId: t, kpiId: kpi.id, period } }, + update: { value }, create: { tenantId: t, kpiId: kpi.id, period, value }, + }); + } + // Upsert derselben Periode → Update statt Duplikat (Unique). + await db.kpiValue.upsert({ where: { tenantId_kpiId_period: { tenantId: t, kpiId: kpi.id, period: "2026-Q2" } }, update: { value: "3%" }, create: { tenantId: t, kpiId: kpi.id, period: "2026-Q2", value: "3%" } }); + const vals = await db.kpiValue.findMany({ where: { kpiId: kpi.id }, orderBy: { period: "asc" } }); + ok(vals.length === 2, `Kennzahl über zwei Perioden auswertbar (${vals.length} Werte, keine Dubletten)`); + ok(vals[1].value === "3%", "Messwert je Periode ist aktualisierbar (Upsert)"); + + // ── 9.3 Managementbewertung entlang 9.3.2 mit Beschlüssen ─────────────────── + const review = await db.managementReview.create({ data: { tenantId: t, reviewDate: new Date("2026-06-01"), inputs: "Kennzahlen, Auditergebnisse, Vorjahresmaßnahmen …", results: "Ressourcen genehmigt" }, select: { id: true } }); + await db.managementReviewDecision.create({ data: { tenantId: t, reviewId: review.id, decision: "Zusätzliche Awareness-Schulung", dueDate: new Date("2026-09-30") } }); + const d2 = await db.managementReviewDecision.create({ data: { tenantId: t, reviewId: review.id, decision: "Backup-Konzept prüfen" }, select: { id: true } }); + await db.managementReviewDecision.update({ where: { id: d2.id }, data: { status: "erledigt" } }); + const withDec = await db.managementReview.findUnique({ where: { id: review.id }, include: { decisions: true } }); + ok(withDec?.decisions.length === 2, "Managementbewertung mit Beschlüssen (Verantwortlicher/Termin) protokollierbar"); + ok(withDec?.decisions.filter((d) => d.status === "erledigt").length === 1, "Beschluss-Status nachverfolgbar (1 erledigt)"); + await db.managementReview.update({ where: { id: review.id }, data: { status: "abgeschlossen" } }); + ok((await db.managementReview.findUnique({ where: { id: review.id } }))?.status === "abgeschlossen", "Managementbewertung abschließbar"); + + // ── 10.2 Nichtkonformität + Korrekturmaßnahme inkl. Wirksamkeit ────────────── + const nc = await db.nonconformity.create({ data: { tenantId: t, refNo: "NC-2026-0001", source: "Internes Audit", description: "Zugriffsrechte nicht rezertifiziert", immediateCorrection: "Sofort-Review" }, select: { id: true } }); + const nc2 = await db.nonconformity.create({ data: { tenantId: t, refNo: "NC-2026-0002", source: "Vorfall", description: "Test" }, select: { refNo: true } }); + ok(nc2.refNo === "NC-2026-0002", "fortlaufende NC-Kennung (NC-2026-0002)"); + const ca = await db.correctiveAction.create({ data: { tenantId: t, nonconformityId: nc.id, action: "Rezertifizierungs-Prozess etablieren", rootCause: "Kein definierter Turnus" }, select: { id: true } }); + // Wirksamkeit dokumentieren + Maßnahme umgesetzt. + await db.correctiveAction.update({ where: { id: ca.id }, data: { status: "umgesetzt", effectivenessCheck: "Rezertifizierung im Folgequartal vollständig", effectivenessConfirmedAt: new Date() } }); + const caAfter = await db.correctiveAction.findUnique({ where: { id: ca.id } }); + ok(!!caAfter?.effectivenessConfirmedAt && !!caAfter?.effectivenessCheck, "Korrekturmaßnahme mit dokumentierter Wirksamkeitsprüfung"); + // Nichtkonformität schließen. + await db.nonconformity.update({ where: { id: nc.id }, data: { status: "abgeschlossen", closedAt: new Date() } }); + const ncAfter = await db.nonconformity.findUnique({ where: { id: nc.id } }); + ok(ncAfter?.status === "abgeschlossen" && !!ncAfter?.closedAt, "Maßnahmenfall inkl. Wirksamkeitsprüfung abschließbar"); + + await cleanup(); + console.log("\n✓ aufgeräumt (Wegwerf-Mandant entfernt)"); +} + +main() + .then(() => { console.log(failures === 0 ? "\nAP4-Managementklauseln grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch(async (e) => { console.error(e); await cleanup().catch(() => {}); process.exit(1); }); diff --git a/scripts/test-rls-enforcement.ts b/scripts/test-rls-enforcement.ts new file mode 100644 index 0000000..c30c62f --- /dev/null +++ b/scripts/test-rls-enforcement.ts @@ -0,0 +1,180 @@ +// Korrektheitsnachweis für F-04: Row Level Security scharfschalten. +// +// Beweist, dass die scharfe RLS (FORCE + WITH CHECK + Kontext, Rolle isms_app) +// die Mandantentrennung erzwingt, OHNE den lokalen Owner-Betrieb zu brechen. +// Fünf Nachweise (jeweils Assertion; am Ende "OK" oder Exit-Code != 0): +// (1) Owner-Betrieb bleibt heil: Owner (Superuser/BYPASSRLS) sieht ohne +// app.tenant_id weiterhin ALLE Zeilen über Mandanten hinweg. +// (2) RLS greift für isms_app: mit Kontext=A nur A-Zeilen, keine von B. +// (3) Ohne Kontext = null Zeilen (fail-closed). +// (4) WITH CHECK wirkt: INSERT mit eigenem Mandanten gelingt, mit fremdem +// Mandanten wird abgelehnt. +// (5) dbForTenant end-to-end mit RLS_ENFORCED=true (dynamischer Import). +// +// Voraussetzung (einmalig lokal): +// docker exec isms-tool-postgres-1 psql -U isms -d isms \ +// -c "ALTER ROLE isms_app WITH LOGIN PASSWORD 'isms_app_local';" +// npx prisma migrate deploy +// +// Lauf: npx tsx scripts/test-rls-enforcement.ts +// Nutzt die lokale Postgres-DB (Container isms-tool-postgres-1); .env im Worktree. + +import "dotenv/config"; +import { PrismaClient } from "@prisma/client"; +import { PrismaPg } from "@prisma/adapter-pg"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; +async function expectThrow(fn: () => Promise, msg: string) { + try { + await fn(); + ok(false, `${msg} — kein Throw (Isolationsbruch möglich!)`); + } catch { + ok(true, msg); + } +} + +const RLS_URL = + process.env.RLS_DATABASE_URL ?? + "postgresql://isms_app:isms_app_local@localhost:5432/isms?schema=public"; + +const SLUG_A = "zz-rls-test-a"; +const SLUG_B = "zz-rls-test-b"; + +// Eigener Owner-Client (DATABASE_URL) für Setup/Cleanup — unabhängig von db.ts, +// damit der spätere dynamische Import von db.ts (mit RLS_ENFORCED=true) sauber +// mit der bereits gesetzten Flag-Umgebung evaluiert. +const owner = new PrismaClient({ + adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), +}); +// Client der eingeschränkten App-Rolle isms_app (unterliegt der scharfen RLS). +const app = new PrismaClient({ + adapter: new PrismaPg({ connectionString: RLS_URL }), +}); + +async function cleanup() { + const tenants = await owner.tenant.findMany({ + where: { slug: { in: [SLUG_A, SLUG_B] } }, + select: { id: true }, + }); + const ids = tenants.map((t) => t.id); + if (ids.length) { + await owner.risk.deleteMany({ where: { tenantId: { in: ids } } }); + await owner.tenant.deleteMany({ where: { id: { in: ids } } }); + } +} + +async function main() { + await cleanup(); + + // Setup: zwei Test-Mandanten mit je einem Risk (über den Owner angelegt). + const tenantA = await owner.tenant.create({ + data: { name: "ZZ RLS Test A", slug: SLUG_A }, + }); + const tenantB = await owner.tenant.create({ + data: { name: "ZZ RLS Test B", slug: SLUG_B }, + }); + const riskA = await owner.risk.create({ + data: { tenantId: tenantA.id, refNo: 9001, title: "Risiko A" }, + }); + const riskB = await owner.risk.create({ + data: { tenantId: tenantB.id, refNo: 9001, title: "Risiko B" }, + }); + + // ── (1) Owner-Betrieb bleibt heil (kritisch für lokal + devB) ────────────── + // Owner ist Superuser/BYPASSRLS → sieht trotz FORCE alle Mandanten, OHNE dass + // app.tenant_id gesetzt ist. + const ownerCount = await owner.risk.count({ + where: { tenantId: { in: [tenantA.id, tenantB.id] } }, + }); + ok( + ownerCount === 2, + `(1) Owner sieht ohne Kontext beide Mandanten (${ownerCount}/2) — FORCE bricht Owner-Betrieb nicht`, + ); + const ownerTotal = await owner.risk.count(); + ok(ownerTotal > 0, `(1b) Owner sieht global Zeilen (${ownerTotal} > 0)`); + + // ── (2) RLS greift für isms_app: mit Kontext=A nur A-Zeilen ──────────────── + const seenA = await app.$transaction(async (tx) => { + await tx.$executeRaw`SELECT set_config('app.tenant_id', ${tenantA.id}, true)`; + return tx.risk.findMany({ select: { id: true, tenantId: true } }); + }); + ok( + seenA.length > 0 && + seenA.every((r) => r.tenantId === tenantA.id) && + seenA.some((r) => r.id === riskA.id) && + !seenA.some((r) => r.id === riskB.id), + `(2) isms_app mit Kontext=A sieht nur A-Zeilen (${seenA.length}), keine von B`, + ); + + // ── (3) Ohne Kontext = null Zeilen (fail-closed) ─────────────────────────── + const seenNone = await app.risk.count(); + ok(seenNone === 0, `(3) isms_app ohne Kontext sieht 0 Zeilen (${seenNone})`); + + // ── (4) WITH CHECK wirkt: eigener Mandant erlaubt, fremder abgelehnt ──────── + const inserted = await app.$transaction(async (tx) => { + await tx.$executeRaw`SELECT set_config('app.tenant_id', ${tenantA.id}, true)`; + return tx.risk.create({ + data: { tenantId: tenantA.id, refNo: 9002, title: "Risiko A insert" }, + }); + }); + ok( + inserted.tenantId === tenantA.id, + "(4a) INSERT mit eigenem Mandanten (A) unter Kontext=A gelingt", + ); + await expectThrow( + () => + app.$transaction(async (tx) => { + await tx.$executeRaw`SELECT set_config('app.tenant_id', ${tenantA.id}, true)`; + // Fremder Mandant B unter Kontext A → WITH-CHECK-Policy lehnt ab. + return tx.risk.create({ + data: { tenantId: tenantB.id, refNo: 9003, title: "Fremd-Insert" }, + }); + }), + "(4b) INSERT mit fremdem Mandanten (B) unter Kontext=A wird von WITH CHECK abgelehnt", + ); + + // ── (5) dbForTenant end-to-end mit RLS_ENFORCED=true ─────────────────────── + // Flag + URL VOR dem Import von db.ts setzen (dynamischer Import). + process.env.RLS_ENFORCED = "true"; + process.env.RLS_DATABASE_URL = RLS_URL; + const db = await import("../src/server/db"); + + const e2eA = await db.dbForTenant(tenantA.id).risk.findMany({ + select: { id: true, tenantId: true }, + }); + ok( + e2eA.length > 0 && + e2eA.every((r) => r.tenantId === tenantA.id) && + !e2eA.some((r) => r.id === riskB.id), + `(5a) dbForTenant(A).risk.findMany() liefert nur A (${e2eA.length})`, + ); + const foreign = await db.dbForTenant(tenantA.id).risk.findFirst({ + where: { id: riskB.id }, + }); + ok( + foreign === null, + "(5b) dbForTenant(A).risk.findFirst({ id: B-Risk }) → null (kein Fremdzugriff)", + ); + + await cleanup(); + + if (failures > 0) { + console.error(`\n${failures} Nachweis(e) fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK — alle F-04-Nachweise (1)-(5) erfüllt."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await owner.$disconnect(); + await app.$disconnect(); + }); diff --git a/scripts/test-rules.ts b/scripts/test-rules.ts new file mode 100644 index 0000000..f5b498d --- /dev/null +++ b/scripts/test-rules.ts @@ -0,0 +1,102 @@ +// Akzeptanztest der Regel-Engine (Story F3/B2). Deterministische Assertions gegen +// C2 §5 (Q-FEAT-01…10) und §8 (Aufgaben-Trigger). Kein DB-Zugriff, reine Logik. +// Lauf: npx tsx scripts/test-rules.ts (Exit 1 bei Fehler). + +import { evaluateRules, makeContext } from "../src/lib/rules/engine"; +import { ALL_RULES, FEATURE_RULES, Q } from "../src/lib/rules/feature-rules"; +import { triggerById } from "../src/lib/task-triggers"; +import type { Answer } from "../src/lib/rules/dsl"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const evalAnswers = (answers: Record, pruefziele?: string[]) => + evaluateRules(ALL_RULES, makeContext({ answers, ...(pruefziele ? { pruefziele } : {}) })); + +// — Q-FEAT-02 Cloud — +{ + const on = evalAnswers({ [Q.CLOUD]: true }); + ok(on.flags.FLAG_CLOUD_USED === true, "Q-FEAT-02=ja → FLAG_CLOUD_USED"); + ok(["5.3.2", "5.3.4", "6.1.3"].every((c) => on.controls.includes(c)), "Q-FEAT-02=ja → Controls 5.3.2/5.3.4/6.1.3"); + ok(on.risks.includes("R-CLOUD"), "Q-FEAT-02=ja → Risiko R-CLOUD"); + ok(on.matched.includes("feat02-cloud"), "Q-FEAT-02=ja → Regel feat02-cloud ausgelöst"); + const off = evalAnswers({ [Q.CLOUD]: false }); + ok(off.flags.FLAG_CLOUD_USED !== true, "Q-FEAT-02=nein → kein FLAG_CLOUD_USED"); + ok(!off.matched.includes("feat02-cloud"), "Q-FEAT-02=nein → feat02-cloud NICHT ausgelöst"); + ok(!off.controls.includes("5.3.2"), "Q-FEAT-02=nein → Control 5.3.2 nicht im Scope"); +} + +// — A2-1: Schutzbedarf kommt zentral aus dem Assessment-Level (Seed), NICHT aus dem Fragebogen — +{ + // Ohne AL-Seed setzt keine Fragebogen-Antwort HIGH/VERY_HIGH. + const noSeed = evalAnswers({ [Q.CLOUD]: true, [Q.EXTERNAL_IT]: true }); + ok(noSeed.flags.FLAG_HIGH_PROTECTION !== true && noSeed.flags.FLAG_VERY_HIGH_PROTECTION !== true, "Fragebogen setzt HIGH/VERY_HIGH nicht"); + ok(noSeed.flags.FLAG_ELEVATED_PROTECTION === false, "ohne AL-Seed → ELEVATED aus"); + // AL2-Seed → HIGH an, VERY_HIGH aus; AL3-Seed → beide an; ELEVATED jeweils abgeleitet. + const al2 = evaluateRules(ALL_RULES, makeContext({ flags: { FLAG_HIGH_PROTECTION: true, FLAG_VERY_HIGH_PROTECTION: false } })); + ok(al2.flags.FLAG_HIGH_PROTECTION === true && al2.flags.FLAG_VERY_HIGH_PROTECTION !== true, "AL2-Seed → HIGH an, VERY_HIGH aus"); + ok(al2.flags.FLAG_ELEVATED_PROTECTION === true, "AL2-Seed → ELEVATED abgeleitet an"); + const al3 = evaluateRules(ALL_RULES, makeContext({ flags: { FLAG_HIGH_PROTECTION: true, FLAG_VERY_HIGH_PROTECTION: true } })); + ok(al3.flags.FLAG_VERY_HIGH_PROTECTION === true && al3.flags.FLAG_ELEVATED_PROTECTION === true, "AL3-Seed → VERY_HIGH + ELEVATED an"); +} + +// — Q-FEAT-09 externe IT (Control + Risiko + Aufgabe) — +{ + const r = evalAnswers({ [Q.EXTERNAL_IT]: true }); + ok(r.flags.FLAG_EXTERNAL_IT === true, "Q-FEAT-09=ja → FLAG_EXTERNAL_IT"); + ok(r.controls.includes("6.1.1") && r.controls.includes("6.1.3"), "Q-FEAT-09=ja → Controls 6.1.1/6.1.3"); + ok(r.risks.includes("R-SUP"), "Q-FEAT-09=ja → Risiko R-SUP"); + ok(r.tasks.includes("external_it_yes"), "Q-FEAT-09=ja → Aufgabe external_it_yes"); +} + +// — C2 §8 Aufgaben-Trigger — +{ + const cloud = evalAnswers({ [Q.CLOUD]: true }); + ok(cloud.tasks.includes("cloud_ai_without_approval"), "Cloud=ja → Aufgabe cloud_ai_without_approval"); + const ai = evalAnswers({ [Q.AI]: true }); + ok(ai.tasks.includes("cloud_ai_without_approval"), "KI=ja → Aufgabe cloud_ai_without_approval"); + const neither = evalAnswers({ [Q.CLOUD]: false, [Q.AI]: false }); + ok(!neither.tasks.includes("cloud_ai_without_approval"), "Cloud/KI=nein → keine Freigabeverfahren-Aufgabe"); + const isb = evalAnswers({ [Q.ISB_BENANNT]: false }); + ok(isb.tasks.includes("isb_not_named"), "ISB nicht benannt → Aufgabe isb_not_named"); + const restore = evalAnswers({ [Q.RESTORE_GETESTET]: false }); + ok(restore.tasks.includes("no_restore_test"), "kein Restore-Test → Aufgabe no_restore_test"); +} + +// — Determinismus: gleiche Eingabe → gleiches Ergebnis — +{ + const a = evalAnswers({ [Q.CLOUD]: true, [Q.EXTERNAL_IT]: true }); + const b = evalAnswers({ [Q.CLOUD]: true, [Q.EXTERNAL_IT]: true }); + ok(JSON.stringify(a) === JSON.stringify(b), "Determinismus: identische Auswertung bei gleicher Eingabe"); +} + +// — Integrität: alle referenzierten Trigger-IDs existieren im Katalog (B1) — +{ + const taskIds = new Set(ALL_RULES.flatMap((r) => r.effect.tasks ?? [])); + const allExist = [...taskIds].every((id) => triggerById(id) !== null); + ok(allExist, `alle Aufgaben-Trigger-IDs existieren in task-triggers.ts (${[...taskIds].join(", ")})`); +} + +// — Abdeckung: jede Q-FEAT-02…10 hat eine Regel (Q-FEAT-01/Schutzbedarf ist zentral, A2-1) — +{ + const covered = new Set(FEATURE_RULES.map((r) => r.source)); + const missing = Array.from({ length: 9 }, (_, i) => `C2 §5 Q-FEAT-${String(i + 2).padStart(2, "0")}`).filter((s) => !covered.has(s)); + ok(missing.length === 0, `alle Q-FEAT-02…10 durch Regeln abgedeckt${missing.length ? " — fehlt: " + missing.join(", ") : ""}`); +} + +// — Follow-up: Prüfziele kommen aus WizardScope (Scoping), nicht aus dem Fragebogen — +{ + const ds = evalAnswers({}, ["informationssicherheit", "datenschutz"]); + ok(ds.flags.FLAG_PERSONAL_DATA === true, "Prüfziel Datenschutz → FLAG_PERSONAL_DATA"); + ok(ds.controls.includes("7.1.2") && ds.risks.includes("R-DSGVO"), "Prüfziel Datenschutz → Control 7.1.2 + Risiko R-DSGVO"); + const proto = evalAnswers({}, ["informationssicherheit", "prototypenschutz"]); + ok(proto.flags.FLAG_PROTOTYPE_PROTECTION === true, "Prüfziel Prototypenschutz → FLAG_PROTOTYPE_PROTECTION"); + const isOnly = evalAnswers({}, ["informationssicherheit"]); + ok(isOnly.flags.FLAG_PERSONAL_DATA !== true && isOnly.flags.FLAG_PROTOTYPE_PROTECTION !== true, "nur Informationssicherheit → Datenschutz/Prototyp-Flags aus"); +} + +console.log(failures === 0 ? "\nOK — alle Regel-Tests grün" : `\nPRUEFEN — ${failures} Fehler`); +process.exit(failures === 0 ? 0 : 1); diff --git a/scripts/test-scope-filter.ts b/scripts/test-scope-filter.ts new file mode 100644 index 0000000..d46a121 --- /dev/null +++ b/scripts/test-scope-filter.ts @@ -0,0 +1,72 @@ +// Akzeptanztest des Scope-Filters (Story A2-2). Repräsentative C1-Zeilen + Scope- +// Dynamik. Reine Logik, kein DB-Zugriff. Lauf: npx tsx scripts/test-scope-filter.ts + +import { C1_ROWS, activeRequirements, isRequirementActive, scopeSummary, type Pruefziel } from "../src/lib/scope-filter"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const row = (id: string) => { + const r = C1_ROWS.find((x) => x.id === id); + if (!r) throw new Error(`C1-Zeile ${id} nicht gefunden`); + return r; +}; + +// Flag-Sets: HIGH ist AL2-Baseline, VERY_HIGH nur AL3 (A2-1). +const AL2 = { FLAG_HIGH_PROTECTION: true, FLAG_VERY_HIGH_PROTECTION: false, FLAG_ELEVATED_PROTECTION: true }; +const AL3 = { FLAG_HIGH_PROTECTION: true, FLAG_VERY_HIGH_PROTECTION: true, FLAG_ELEVATED_PROTECTION: true }; +const SHOULD = { FLAG_INCLUDE_SHOULD: true }; +const IS: Pruefziel[] = ["informationssicherheit"]; + +// — Grunddaten — +ok(C1_ROWS.length === 412, `C1-Datengrundlage: 412 Anforderungen (${C1_ROWS.length})`); + +// — MUSS (immer im Scope) — +ok(isRequirementActive(row("1.1.1-M1"), { pruefziele: IS, flags: {} }), "1.1.1-M1 (MUSS) → im Scope ohne Flags"); + +// — SOLL nur bei FLAG_INCLUDE_SHOULD — +ok(!isRequirementActive(row("1.1.1-S1"), { pruefziele: IS, flags: { ...AL2 } }), "1.1.1-S1 (SOLL) → NICHT ohne FLAG_INCLUDE_SHOULD"); +ok(isRequirementActive(row("1.1.1-S1"), { pruefziele: IS, flags: { ...AL2, ...SHOULD } }), "1.1.1-S1 (SOLL) → im Scope mit FLAG_INCLUDE_SHOULD"); + +// — HOCH nur bei FLAG_HIGH_PROTECTION — +ok(!isRequirementActive(row("1.2.2-H1"), { pruefziele: IS, flags: { FLAG_HIGH_PROTECTION: false } }), "1.2.2-H1 (HOCH) → NICHT ohne FLAG_HIGH_PROTECTION"); +ok(isRequirementActive(row("1.2.2-H1"), { pruefziele: IS, flags: { ...AL2 } }), "1.2.2-H1 (HOCH) → im Scope bei AL2 (HIGH-Baseline)"); + +// — SEHR HOCH nur bei FLAG_VERY_HIGH_PROTECTION (AL3) — +ok(!isRequirementActive(row("1.3.4-V1"), { pruefziele: IS, flags: { ...AL2 } }), "1.3.4-V1 (SEHR HOCH) → NICHT bei AL2"); +ok(isRequirementActive(row("1.3.4-V1"), { pruefziele: IS, flags: { ...AL3 } }), "1.3.4-V1 (SEHR HOCH) → im Scope bei AL3"); + +// — Kapitel 8.x nur bei Prüfziel Prototypenschutz — +ok(!isRequirementActive(row("8.1.1-M1"), { pruefziele: IS, flags: { ...AL3, ...SHOULD } }), "8.1.1-M1 → NICHT ohne Prüfziel Prototypenschutz"); +ok(isRequirementActive(row("8.1.1-M1"), { pruefziele: [...IS, "prototypenschutz"], flags: {} }), "8.1.1-M1 → im Scope bei Prüfziel Prototypenschutz"); + +// — Kapitel 9.x nur bei Prüfziel Datenschutz — +ok(!isRequirementActive(row("9.1.1-M1"), { pruefziele: IS, flags: { ...AL3, ...SHOULD } }), "9.1.1-M1 → NICHT ohne Prüfziel Datenschutz"); +ok(isRequirementActive(row("9.1.1-M1"), { pruefziele: [...IS, "datenschutz"], flags: {} }), "9.1.1-M1 → im Scope bei Prüfziel Datenschutz"); + +// — Scope-Dynamik (Kennzahlen) — +const al2 = scopeSummary({ pruefziele: IS, flags: { ...AL2, ...SHOULD } }); +const al3 = scopeSummary({ pruefziele: IS, flags: { ...AL3, ...SHOULD } }); +ok(al3.total > al2.total, `AL3 hat mehr Anforderungen als AL2 (${al3.total} > ${al2.total}) — SEHR HOCH kommt hinzu`); +ok(al3.total - al2.total === al3.byType["SEHR HOCH"], "AL3−AL2 == Anzahl SEHR HOCH (nur SEHR HOCH unterscheidet sich)"); + +const noShould = scopeSummary({ pruefziele: IS, flags: { ...AL2 } }); +ok(al2.total - noShould.total === al2.byType.SOLL, "FLAG_INCLUDE_SHOULD schaltet genau die SOLL-Anforderungen"); + +const withProto = scopeSummary({ pruefziele: [...IS, "prototypenschutz"], flags: { ...AL3, ...SHOULD } }); +ok(withProto.total > al3.total, `Prüfziel Prototypenschutz erhöht den Scope (${withProto.total} > ${al3.total})`); +ok((withProto.byPruefziel["prototypenschutz"] ?? 0) > 0 && !al3.byPruefziel["prototypenschutz"], "Prototyp-Anforderungen nur bei aktivem Prüfziel"); + +// — Volles Prüfziel-/Flag-Set = alle 412 — +const all = scopeSummary({ pruefziele: ["informationssicherheit", "prototypenschutz", "datenschutz"], flags: { ...AL3, ...SHOULD } }); +ok(all.total === 412, `alle Prüfziele + AL3 + SOLL → alle 412 Anforderungen im Scope (${all.total})`); + +// — Nur MUSS (keine Flags, nur IS) — +const mussOnly = activeRequirements({ pruefziele: IS, flags: {} }); +ok(mussOnly.every((r) => r.type === "MUSS"), "ohne Flags/Zusatz-Prüfziele → nur MUSS (IS)"); + +console.log(failures === 0 ? "\nOK — alle Scope-Filter-Tests grün" : `\nPRUEFEN — ${failures} Fehler`); +process.exit(failures === 0 ? 0 : 1); diff --git a/scripts/test-soa.ts b/scripts/test-soa.ts new file mode 100644 index 0000000..b947a96 --- /dev/null +++ b/scripts/test-soa.ts @@ -0,0 +1,67 @@ +// AP3 — Anwendbarkeitserklärung (SoA). Prüft Vorbefüllung, Bedingungs-Logik, +// Idempotenz und Vollständigkeits-Markierung gegen die lokale DB (Wegwerf-Mandant). +// +// Lauf: npx tsx scripts/test-soa.ts + +import "dotenv/config"; +import { prisma, dbForTenant } from "../src/server/db"; +import { ensureSoaEntries, loadIsoSoaControls } from "../src/server/soa-statement"; +import { isSoaEntryComplete } from "../src/lib/soa"; + +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; +const SLUG = "ap3-test-soa"; + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG }, select: { id: true } }); + if (t) { + await prisma.soaEntry.deleteMany({ where: { tenantId: t.id } }); + await prisma.policyVariable.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); + } +} + +async function main() { + await cleanup(); + + const controls = loadIsoSoaControls(); + ok(controls.length === 93, `loadIsoSoaControls: ${controls.length} Annex-A-Controls (erwartet 93)`); + const devControl = controls.find((c) => c.condition === "FLAG_DEV_INHOUSE"); + const plainControl = controls.find((c) => c.condition === null); + ok(!!devControl && !!plainControl, "je ein Control mit/ohne Bedingung vorhanden"); + + const tenant = await prisma.tenant.create({ data: { name: "AP3 SoA", slug: SLUG } }); + const t = tenant.id; + // Flags: DEV-Inhouse AUS → DEV-Controls default nicht anwendbar; Personendaten AN. + await prisma.policyVariable.createMany({ + data: [ + { tenantId: t, key: "FLAG_DEV_INHOUSE", title: "Dev", kind: "boolean", value: "false" }, + { tenantId: t, key: "FLAG_PERSONAL_DATA", title: "PD", kind: "boolean", value: "true" }, + ], + }); + const db = dbForTenant(t); + + const n1 = await ensureSoaEntries(db, t); + ok(n1 === 93, `ensureSoaEntries legt 93 Zeilen an (${n1})`); + const n2 = await ensureSoaEntries(db, t); + ok(n2 === 0, "zweiter Lauf ist idempotent (0 neue Zeilen)"); + ok((await prisma.soaEntry.count({ where: { tenantId: t } })) === 93, "93 SoA-Zeilen persistiert"); + + const devEntry = await prisma.soaEntry.findFirst({ where: { tenantId: t, control: devControl!.control } }); + ok(devEntry?.applicable === false, `Bedingung greift: ${devControl!.control} (FLAG_DEV_INHOUSE aus) → nicht anwendbar`); + const plainEntry = await prisma.soaEntry.findFirst({ where: { tenantId: t, control: plainControl!.control } }); + ok(plainEntry?.applicable === true, `Control ohne Bedingung (${plainControl!.control}) → anwendbar`); + + // Vollständigkeit: frisch ohne Begründung → unvollständig; nach Begründung → vollständig. + ok(!isSoaEntryComplete({ applicable: true, justification: "" }), "Control ohne Begründung → unvollständig"); + ok(isSoaEntryComplete({ applicable: false, justification: "Ausschluss: keine Eigenentwicklung" }), "Ausschluss mit Begründung → vollständig"); + const incomplete = await prisma.soaEntry.count({ where: { tenantId: t, justification: "" } }); + ok(incomplete === 93, "alle 93 Zeilen initial ohne Begründung (unvollständig)"); + + await cleanup(); + console.log("\n✓ aufgeräumt (Wegwerf-Mandant entfernt)"); +} + +main() + .then(() => { console.log(failures === 0 ? "\nAP3-SoA grün." : `\n${failures} Prüfung(en) fehlgeschlagen.`); process.exit(failures === 0 ? 0 : 1); }) + .catch(async (e) => { console.error(e); await cleanup().catch(() => {}); process.exit(1); }); diff --git a/scripts/test-tenant-isolation.ts b/scripts/test-tenant-isolation.ts new file mode 100644 index 0000000..7424c91 --- /dev/null +++ b/scripts/test-tenant-isolation.ts @@ -0,0 +1,159 @@ +// Regressionstest der Mandantentrennung (Sicherheitsbefund F-02). +// +// Prüft den Hybrid-Guard aus `src/server/db.ts` (`dbForTenant`): ein Fremdzugriff +// über `findUnique` darf keinen Datensatz eines anderen Mandanten preisgeben — +// weder mit `select`-Projektion ohne `tenantId` (der ursprünglich ausnutzbare +// Fall), noch mit `include`, ohne `select` oder über einen Compound-Unique-Key. +// Der legitime Eigenzugriff muss unverändert funktionieren. +// +// Lauf: npx tsx scripts/test-tenant-isolation.ts +// Nutzt die lokale Postgres-DB (Container isms-tool-postgres-1); .env liegt im Worktree. + +import "dotenv/config"; +import { prisma, dbForTenant } from "../src/server/db"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +/** Erwartet, dass `fn` wirft (z. B. Isolationsverletzung oder NotFound). */ +async function expectThrow(fn: () => Promise, msg: string) { + try { + await fn(); + ok(false, `${msg} — kein Throw (Datenabfluss möglich!)`); + } catch { + ok(true, msg); + } +} + +/** Erwartet, dass `fn` `null` liefert (kein Datensatz, kein Abfluss). */ +async function expectNull(fn: () => Promise, msg: string) { + const r = await fn(); + ok(r === null, `${msg}${r === null ? "" : ` — statt null: ${JSON.stringify(r)}`}`); +} + +const SLUG_A = "zz-sec-test-a"; +const SLUG_B = "zz-sec-test-b"; + +async function cleanup() { + const tenants = await prisma.tenant.findMany({ + where: { slug: { in: [SLUG_A, SLUG_B] } }, + select: { id: true }, + }); + const ids = tenants.map((t) => t.id); + if (ids.length) { + await prisma.risk.deleteMany({ where: { tenantId: { in: ids } } }); + await prisma.tenant.deleteMany({ where: { id: { in: ids } } }); + } +} + +async function main() { + // Idempotenz: eventuelle Reste eines früheren Laufs entfernen. + await cleanup(); + + // Zwei Test-Mandanten mit je einem Risiko anlegen (roher Client = ohne Guard). + const tenantA = await prisma.tenant.create({ data: { name: "SEC-Test A", slug: SLUG_A } }); + const tenantB = await prisma.tenant.create({ data: { name: "SEC-Test B", slug: SLUG_B } }); + + const riskA = await prisma.risk.create({ + data: { tenantId: tenantA.id, refNo: 900001, title: "Risiko A (eigen)", likelihood: 3, impact: 3, score: 9 }, + }); + const riskB = await prisma.risk.create({ + data: { tenantId: tenantB.id, refNo: 900001, title: "GEHEIM-B (fremd)", likelihood: 4, impact: 4, score: 16 }, + }); + + const dbA = dbForTenant(tenantA.id); + + console.log("\n— Fremdzugriff (Mandant A liest Risiko von B) muss scheitern —"); + + // (1) Der ursprüngliche Exploit: select-Projektion OHNE tenantId. + await expectNull( + () => dbA.risk.findUnique({ where: { id: riskB.id }, select: { refNo: true, title: true } }), + "findUnique + select OHNE tenantId → null (F-02-Kernfall)" + ); + + // (2) select MIT tenantId. + await expectNull( + () => dbA.risk.findUnique({ where: { id: riskB.id }, select: { title: true, tenantId: true } }), + "findUnique + select MIT tenantId → null" + ); + + // (3) include (tenantId wäre ohnehin enthalten). + await expectNull( + () => dbA.risk.findUnique({ where: { id: riskB.id }, include: { riskMeasures: true } }), + "findUnique + include → null" + ); + + // (4) ohne select/include. + await expectNull( + () => dbA.risk.findUnique({ where: { id: riskB.id } }), + "findUnique ohne Projektion → null" + ); + + // (5) findUniqueOrThrow → muss werfen statt fremden Datensatz zu liefern. + await expectThrow( + () => dbA.risk.findUniqueOrThrow({ where: { id: riskB.id }, select: { title: true } }), + "findUniqueOrThrow + select OHNE tenantId → Throw" + ); + + // (6) Compound-Unique-Key (tenantId_refNo) mit fremdem tenantId, select ohne tenantId. + await expectThrow( + () => + dbA.risk.findUnique({ + where: { tenantId_refNo: { tenantId: tenantB.id, refNo: riskB.refNo } }, + select: { title: true }, + }), + "findUnique über Compound-Key (fremd) + select → Throw (fail-closed)" + ); + + // (7) Compound-Unique-Key mit fremdem tenantId, ohne select. + await expectThrow( + () => + dbA.risk.findUnique({ + where: { tenantId_refNo: { tenantId: tenantB.id, refNo: riskB.refNo } }, + }), + "findUnique über Compound-Key (fremd) ohne select → Throw" + ); + + console.log("\n— Legitimer Eigenzugriff (Mandant A liest eigenes Risiko A) muss funktionieren —"); + + // (8) skalarer Key + select: Treffer, und tenantId darf NICHT auftauchen (kein Injektions-Leck). + const own1 = await dbA.risk.findUnique({ where: { id: riskA.id }, select: { title: true } }); + ok(own1?.title === riskA.title, "Eigenzugriff findUnique + select → Treffer"); + ok(own1 !== null && !("tenantId" in (own1 as object)), "Eigenzugriff select {title} → Rückgabe OHNE tenantId"); + + // (9) Compound-Key (eigen) + select: Treffer, injiziertes tenantId wieder entfernt. + const own2 = await dbA.risk.findUnique({ + where: { tenantId_refNo: { tenantId: tenantA.id, refNo: riskA.refNo } }, + select: { title: true }, + }); + ok(own2?.title === riskA.title, "Eigenzugriff über Compound-Key + select → Treffer"); + ok(own2 !== null && !("tenantId" in (own2 as object)), "Compound-Key select {title} → Rückgabe OHNE tenantId (Injektion bereinigt)"); + + // (10) ohne Projektion: voller Datensatz inkl. tenantId (Normalfall). + const own3 = await dbA.risk.findUnique({ where: { id: riskA.id } }); + ok(own3?.tenantId === tenantA.id, "Eigenzugriff ohne Projektion → voller Datensatz inkl. tenantId"); + + // (11) findUniqueOrThrow auf eigenen Datensatz → kein Throw. + const own4 = await dbA.risk.findUniqueOrThrow({ where: { id: riskA.id }, select: { title: true } }); + ok(own4.title === riskA.title, "Eigenzugriff findUniqueOrThrow → Treffer"); +} + +main() + .then(async () => { + await cleanup(); + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-tenant-switch.ts b/scripts/test-tenant-switch.ts new file mode 100644 index 0000000..bf69d93 --- /dev/null +++ b/scripts/test-tenant-switch.ts @@ -0,0 +1,71 @@ +// WS2-Abnahmetest (Option C) — Mandantenwechsel: server-autoritative Auflösung. +// +// `resolveActiveMembership(identityId, membershipId)` ist der Kern von setActiveTenant +// (und des jwt-„update"-Triggers). Geprüft: +// 1. Eine Mitgliedschaft der eigenen Identity wird aufgelöst (Mandant + Rechte). +// 2. Rechte werden je Mandant NEU aufgelöst (demo user ≠ demo2 tenant-admin) — +// Nachweis der Wechsel-Isolation (keine token-eingefrorenen Fremdrechte). +// 3. Eine FREMDE Mitgliedschaft (andere Identity) wird abgelehnt (null). +// 4. Eine unbekannte Membership-ID wird abgelehnt (null). +// +// Lauf: npx tsx scripts/test-tenant-switch.ts (setzt den Demo-Seed voraus) + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { resolveActiveMembership } from "../src/server/auth"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function main() { + const multi = await prisma.identity.findUniqueOrThrow({ + where: { email: "multi@demo.example" }, + include: { memberships: { include: { tenant: true } } }, + }); + const inDemo = multi.memberships.find((m) => m.tenant.slug === "demo")!; + const inDemo2 = multi.memberships.find((m) => m.tenant.slug === "demo2")!; + + console.log("\n— 1/2) Auflösung + Rechte je Mandant (Wechsel-Isolation) —"); + const demo = await resolveActiveMembership(multi.id, inDemo.id); + const demo2 = await resolveActiveMembership(multi.id, inDemo2.id); + ok(demo?.tenantSlug === "demo", `demo-Mitgliedschaft → Mandant demo (${demo?.tenantSlug})`); + ok(demo2?.tenantSlug === "demo2", `demo2-Mitgliedschaft → Mandant demo2 (${demo2?.tenantSlug})`); + ok(demo?.roles.includes("user") ?? false, "in demo: Rolle user"); + ok(demo2?.roles.includes("tenant-admin") ?? false, "in demo2: Rolle tenant-admin"); + ok( + JSON.stringify([...(demo?.permissions ?? [])].sort()) !== JSON.stringify([...(demo2?.permissions ?? [])].sort()), + "Rechte je Mandant verschieden (neu aufgelöst, nicht token-eingefroren)" + ); + ok(demo?.activeMembershipId === inDemo.id, "activeMembershipId = gewählte Mitgliedschaft"); + + console.log("\n— 3) Fremde Mitgliedschaft wird abgelehnt —"); + // admin@demo ist eine ANDERE Identity; ihre Mitgliedschaft darf multi@ nicht aktivieren. + const admin = await prisma.identity.findUniqueOrThrow({ + where: { email: "admin@demo.example" }, + include: { memberships: { select: { id: true } } }, + }); + const foreign = await resolveActiveMembership(multi.id, admin.memberships[0]!.id); + ok(foreign === null, "Mitgliedschaft einer fremden Identity ⇒ null"); + + console.log("\n— 4) Unbekannte Membership-ID —"); + const missing = await resolveActiveMembership(multi.id, "does-not-exist"); + ok(missing === null, "unbekannte Membership-ID ⇒ null"); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-tenant-users-authz.ts b/scripts/test-tenant-users-authz.ts new file mode 100644 index 0000000..137245c --- /dev/null +++ b/scripts/test-tenant-users-authz.ts @@ -0,0 +1,142 @@ +// Nachweis der Rechte-Begrenzung bei der Rollenverwaltung (Sicherheitsbefund F-13). +// +// F-13: Ein `role:manage`-Inhaber (z. B. tenant-admin) konnte über `createRole`/ +// `updateRolePermissions` eine Rolle mit BELIEBIGEN Katalog-Rechten bauen und sie sich +// über `setUserRoles` selbst zuweisen — obwohl der tenant-admin bewusst NICHT über +// `policy:approve`/`risk:accept`/`soa:write` verfügt. Der Fix begrenzt vergebbare Rechte +// auf die eigene effektive Rechtemenge (autoritativ aus der DB) und unterbindet die +// Selbstzuweisung höher privilegierter Rollen. +// +// Dieser Test repliziert exakt die autoritative Query und die Begrenzungslogik aus +// src/server/actions/tenant-users.ts (actorEffectivePermissions / assertGrantableWithinActor / +// Selbstzuweisungs-Prüfung) und weist nach, dass die Entscheidungen korrekt kippen. +// (Ein direkter Action-Aufruf würde eine NextAuth-Session voraussetzen; die sicherheits- +// relevante Logik ist die Query + die Mengenprüfung.) +// +// Lauf: npx tsx scripts/test-tenant-users-authz.ts + +import "dotenv/config"; +import { prisma } from "../src/server/db"; + +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +const SLUG = "zz-f13-authz-test"; + +// Repliziert actorEffectivePermissions() aus tenant-users.ts. +async function effectivePermissions(userId: string): Promise> { + const account = await prisma.user.findFirst({ + where: { id: userId, status: "ACTIVE" }, + select: { + userRoles: { + select: { role: { select: { rolePermissions: { select: { permission: { select: { key: true } } } } } } }, + }, + }, + }); + if (!account) throw new Error("Konto ist nicht aktiv."); + return new Set(account.userRoles.flatMap((ur) => ur.role.rolePermissions.map((rp) => rp.permission.key))); +} + +// Repliziert assertGrantableWithinActor() aus tenant-users.ts (Verstoß = excess nicht leer). +const excessOf = (perms: string[], effective: Set) => perms.filter((p) => !effective.has(p)); + +async function cleanup() { + const t = await prisma.tenant.findUnique({ where: { slug: SLUG } }); + if (!t) return; + await prisma.user.deleteMany({ where: { tenantId: t.id } }); + await prisma.role.deleteMany({ where: { tenantId: t.id } }); + await prisma.tenant.delete({ where: { id: t.id } }); + // Verwaiste Test-Identity(s) entfernen (Membership wurde eben gelöscht). + await prisma.identity.deleteMany({ where: { email: { endsWith: "@zz-authz.test" }, memberships: { none: {} } } }); +} + +async function ensurePerm(key: string) { + return prisma.permission.upsert({ where: { key }, update: {}, create: { key } }); +} + +async function main() { + await cleanup(); + + const tenant = await prisma.tenant.create({ data: { name: "F13 AuthZ Test", slug: SLUG } }); + + // tenant-admin-typische Rechte (bewusst OHNE policy:approve / risk:accept / soa:write). + const adminPermKeys = ["tenant:manage", "user:read", "user:manage", "role:manage", "report:read"]; + const adminPerms = await Promise.all(adminPermKeys.map(ensurePerm)); + const escalationTargets = await Promise.all(["policy:approve", "risk:accept", "soa:write"].map(ensurePerm)); + + const adminRole = await prisma.role.create({ + data: { + tenantId: tenant.id, + key: "tenant-admin", + name: "Mandanten-Admin", + rolePermissions: { create: adminPerms.map((p) => ({ permissionId: p.id })) }, + }, + }); + // Option C: Mitgliedschaft braucht eine globale Identity (Anmeldung). + const actorIdentity = await prisma.identity.create({ data: { email: "f13-admin@zz-authz.test", passwordHash: "x" } }); + const actor = await prisma.user.create({ + data: { + tenantId: tenant.id, identityId: actorIdentity.id, email: "f13-admin@zz-authz.test", name: "F13 Admin", + status: "ACTIVE", userRoles: { create: [{ roleId: adminRole.id }] }, + }, + }); + + // Höher privilegierte Rolle (ISB-artig), die der Actor sich NICHT selbst geben darf. + const isbRole = await prisma.role.create({ + data: { + tenantId: tenant.id, key: "isb", name: "ISB / CISO", + rolePermissions: { create: escalationTargets.map((p) => ({ permissionId: p.id })) }, + }, + }); + + const effective = await effectivePermissions(actor.id); + + // (1) Effektive Menge stimmt und enthält bewusst NICHT die kritischen Rechte. + ok(effective.has("role:manage"), "(1) Actor hat role:manage"); + ok(!effective.has("policy:approve") && !effective.has("risk:accept") && !effective.has("soa:write"), + "(1) Actor hat bewusst KEIN policy:approve/risk:accept/soa:write"); + + // (2) createRole/updateRolePermissions: Delegation ist bewusst ERLAUBT (pragmatische + // F-13-Variante) — ein Admin darf Rollen mit Rechten oberhalb seines Niveaus für ANDERE + // anlegen (z. B. ISB klonen+bearbeiten). Die Escalation-Abwehr sitzt in der Selbst- + // zuweisung (4). Hier nur festhalten, dass die kritischen Rechte tatsächlich außerhalb + // des eigenen Niveaus liegen (sonst wäre der Test bedeutungslos). + ok(excessOf(["policy:approve", "risk:accept"], effective).length === 2, + "(2) policy:approve/risk:accept liegen außerhalb des Actor-Niveaus (Delegation dennoch erlaubt)"); + + // (3) Die für ANDERE delegierbaren Rechte sind nicht künstlich beschnitten. + ok(excessOf(["user:read", "report:read"], effective).length === 0, + "(3) Vergabe eigener Rechte (user:read/report:read) ist ohnehin zulässig"); + + // (4) Selbstzuweisung der höher privilegierten ISB-Rolle → blockiert (Kern-Abwehr). + const isbPerms = new Set( + (await prisma.rolePermission.findMany({ where: { roleId: isbRole.id }, select: { permission: { select: { key: true } } } })) + .map((r) => r.permission.key), + ); + const selfAssignExcess = [...isbPerms].filter((p) => !effective.has(p)); + ok(selfAssignExcess.length > 0, + "(4) Selbstzuweisung der ISB-Rolle bringt Rechte oberhalb des eigenen Niveaus → blockiert"); + + // (5) Selbstzuweisung der eigenen (bereits gehaltenen) Admin-Rolle → erlaubt (⊆ effektiv). + const adminRolePerms = new Set( + (await prisma.rolePermission.findMany({ where: { roleId: adminRole.id }, select: { permission: { select: { key: true } } } })) + .map((r) => r.permission.key), + ); + ok([...adminRolePerms].filter((p) => !effective.has(p)).length === 0, + "(5) Selbstzuweisung der eigenen Admin-Rolle bleibt zulässig (keine Eskalation)"); + + await cleanup(); + + if (failures === 0) console.log("\nOK — alle F-13-Nachweise (1)-(5) erfüllt."); + else console.log(`\n${failures} FEHLER.`); + process.exit(failures === 0 ? 0 : 1); +} + +main().catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + process.exit(1); +}); diff --git a/scripts/test-two-step-login.ts b/scripts/test-two-step-login.ts new file mode 100644 index 0000000..75dd329 --- /dev/null +++ b/scripts/test-two-step-login.ts @@ -0,0 +1,99 @@ +// WS5-Abnahmetest (Option C) — Two-Step-Login (MFA-pending) Bausteine. +// +// Geprüft (die Zustandslogik; die Cookie-/signIn-Verdrahtung ist UI/Runtime): +// 1. verifyIdentityPassword: richtig → {mfaRequired}, falsch → null (kein Orakel), +// MFA-Konto meldet mfaRequired=true. +// 2. verifyIdentityMfa: falscher Code → false, gültiger (Recovery-)Code → true. +// 3. finalizeIdentityLogin: baut die Session NACH Passwort(+MFA)-Prüfung. +// 4. login_ticket: signieren→verifizieren ok; manipuliert → null; abgelaufen → null; +// Zweckbindung (mfa_pending ≠ login_ticket). +// +// Lauf: npx tsx scripts/test-two-step-login.ts (setzt den Demo-Seed voraus) + +import "dotenv/config"; +import { prisma } from "../src/server/db"; +import { hashPassword } from "../src/server/password"; +import { generateRecoveryCodes } from "../src/server/mfa"; +import { verifyIdentityPassword, verifyIdentityMfa, finalizeIdentityLogin } from "../src/server/auth"; +import { signLoginTicket, verifyLoginTicket, signMfaPending, verifyMfaPending } from "../src/server/login-ticket"; + +const PW = "Two-Step-Passwort-1!"; +const A = "ws5-nomfa@demo.example"; +const B = "ws5-mfa@demo.example"; +let failures = 0; +const ok = (cond: boolean, msg: string) => { + console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); + if (!cond) failures++; +}; + +async function cleanup() { + const ids = (await prisma.identity.findMany({ where: { email: { in: [A, B] } }, select: { id: true } })).map((i) => i.id); + if (ids.length) await prisma.auditLog.deleteMany({ where: { actorId: { in: ids } } }); + await prisma.user.deleteMany({ where: { email: { in: [A, B] } } }); + await prisma.identity.deleteMany({ where: { email: { in: [A, B] } } }); +} + +async function mkMember(identityId: string, tenantId: string, roleKey: string, email: string) { + const role = await prisma.role.findFirst({ where: { tenantId, key: roleKey } }); + await prisma.user.create({ + data: { tenantId, identityId, email, name: "WS5", status: "ACTIVE", ...(role ? { userRoles: { create: [{ roleId: role.id }] } } : {}) }, + }); +} + +async function main() { + await cleanup(); + const demo = await prisma.tenant.findUniqueOrThrow({ where: { slug: "demo" } }); + const hash = await hashPassword(PW); + + const idA = await prisma.identity.create({ data: { email: A, passwordHash: hash } }); + await mkMember(idA.id, demo.id, "user", A); + + const { plain, hashed } = await generateRecoveryCodes(5); + const idB = await prisma.identity.create({ + data: { email: B, passwordHash: hash, mfaSecret: "JBSWY3DPEHPK3PXP", mfaEnrolledAt: new Date(), recoveryCodes: hashed }, + }); + await mkMember(idB.id, demo.id, "user", B); + + console.log("\n— 1) Passwort-Schritt (kein Orakel) —"); + const pwA = await verifyIdentityPassword(A, PW); + ok(pwA?.mfaRequired === false, "Konto ohne MFA: mfaRequired=false"); + ok((await verifyIdentityPassword(A, "falsch!!")) === null, "falsches Passwort ⇒ null"); + const pwB = await verifyIdentityPassword(B, PW); + ok(pwB?.mfaRequired === true, "Konto mit MFA: mfaRequired=true (kein Login ohne 2. Schritt)"); + + console.log("\n— 2) MFA-Schritt —"); + ok((await verifyIdentityMfa(idB.id, "000000")) === false, "falscher Code ⇒ false"); + ok((await verifyIdentityMfa(idB.id, plain[0]!)) === true, "gültiger Recovery-Code ⇒ true"); + + console.log("\n— 3) Session erst nach Verifikation —"); + const sessA = await finalizeIdentityLogin(idA.id); + ok(sessA?.tenantSlug === "demo" && sessA?.identityId === idA.id, "finalizeIdentityLogin baut Session (Single-Membership → demo)"); + + console.log("\n— 4) login_ticket: Signatur/Manipulation/Ablauf/Zweck —"); + const ticket = signLoginTicket(idA.id, "demo"); + ok(verifyLoginTicket(ticket)?.identityId === idA.id, "gültiges Ticket verifiziert"); + ok(verifyLoginTicket(ticket + "x") === null, "manipuliertes Ticket ⇒ null"); + ok(verifyLoginTicket(signLoginTicket(idA.id, "demo", -1000)) === null, "abgelaufenes Ticket ⇒ null"); + ok(verifyMfaPending(ticket) === null, "Zweckbindung: login_ticket wird NICHT als mfa_pending akzeptiert"); + const pending = signMfaPending(idB.id, "demo"); + ok(verifyMfaPending(pending)?.identityId === idB.id, "mfa_pending verifiziert (identityId + tenant)"); + ok(verifyLoginTicket(pending) === null, "Zweckbindung: mfa_pending wird NICHT als login_ticket akzeptiert"); + + await cleanup(); +} + +main() + .then(async () => { + await prisma.$disconnect(); + if (failures > 0) { + console.error(`\n✗ ${failures} Testfall/-fälle fehlgeschlagen.`); + process.exit(1); + } + console.log("\nOK"); + }) + .catch(async (e) => { + console.error(e); + await cleanup().catch(() => {}); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/scripts/test-vda-isa.ts b/scripts/test-vda-isa.ts new file mode 100644 index 0000000..ccf1732 --- /dev/null +++ b/scripts/test-vda-isa.ts @@ -0,0 +1,44 @@ +// Akzeptanztest des VDA-ISA-Export-Moduls (Story B7-2, C9 §3). Reine Logik. +// Lauf: npx tsx scripts/test-vda-isa.ts (Exit 1 bei Fehler). + +import { pruefzielOfControl, sortForExport, toCatalogCsv, kennzahlen, type ExportControl } from "../src/lib/export/vda-isa"; + +let failures = 0; +const ok = (c: boolean, m: string) => { console.log(`${c ? "✓" : "✗ FEHLER"} ${m}`); if (!c) failures++; }; + +const mk = (control: string, reifegrad: number | null, bestaetigt: boolean): ExportControl => ({ + control, frage: `Frage ${control}`, reifegrad, bestaetigt, umsetzung: "u", belege: "b", offenePunkte: 0, pruefziel: pruefzielOfControl(control), +}); + +// — Prüfziel-Zuordnung — +ok(pruefzielOfControl("4.1.2") === "informationssicherheit", "4.1.2 → Informationssicherheit"); +ok(pruefzielOfControl("8.1.1") === "prototypenschutz", "8.1.1 → Prototypenschutz"); +ok(pruefzielOfControl("9.2.1") === "datenschutz", "9.2.1 → Datenschutz"); + +// — Sortierung IS → Proto → DS — +{ + const sorted = sortForExport([mk("9.1.1", 2, true), mk("8.1.1", 1, true), mk("1.1.1", 3, true), mk("2.1.1", 2, true)]); + ok(sorted.map((r) => r.control).join(",") === "1.1.1,2.1.1,8.1.1,9.1.1", "Reihenfolge IS→Proto→DS, dann numerisch"); +} + +// — CSV: BOM, Header, Status-Markierung, Semikolon — +{ + const csv = toCatalogCsv([mk("1.1.1", 3, true), mk("1.1.2", null, false)]); + ok(csv.charCodeAt(0) === 0xfeff, "CSV beginnt mit UTF-8-BOM"); + ok(csv.includes("Control-ID;Kontrollfrage/Ziel;Reifegrad;Status"), "Header vorhanden"); + ok(/1\.1\.1;[^;]*;3;bestätigt/.test(csv), "bestätigtes Control mit Reifegrad 3"); + ok(/1\.1\.2;[^;]*;na;unbestätigt/.test(csv), "unbestätigt → na + Markierung"); +} + +// — Kennzahlen: „unbestätigt zählt als 0" — +{ + const k = kennzahlen([mk("1.1.1", 3, true), mk("1.1.2", 3, false), mk("8.1.1", 2, true)]); + ok(k.total === 3 && k.bestaetigt === 2, "total 3, bestätigt 2"); + ok(Math.abs(k.gesamtAvg! - (3 + 0 + 2) / 3) < 1e-9, "Ø gesamt = (3+0+2)/3 (unbestätigt=0)"); + const is = k.jePruefziel.find((p) => p.pruefziel === "informationssicherheit")!; + ok(is.controls === 2 && is.bestaetigt === 1 && Math.abs(is.avg! - 1.5) < 1e-9, "IS: 2 Controls, 1 bestätigt, Ø 1,5"); + ok(k.jePruefziel.some((p) => p.pruefziel === "prototypenschutz"), "Prototyp-Prüfziel vorhanden"); +} + +console.log(failures === 0 ? "\nOK — alle VDA-ISA-Export-Tests grün" : `\nPRUEFEN — ${failures} Fehler`); +process.exit(failures === 0 ? 0 : 1); diff --git a/seed/isms-vorlagenpaket-v2-en/Nachweisregister_zentral.md b/seed/isms-vorlagenpaket-v2-en/Nachweisregister_zentral.md new file mode 100644 index 0000000..8525f83 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/Nachweisregister_zentral.md @@ -0,0 +1,47 @@ +# Central Evidence Register – ISMS {{ORG_NAME}} + +| Document information | Value | +|-----------------------|------| +| Document type | Evidence register (applies to all policies) | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | +| Responsible | {{ROLE_ISB}} | + +## Purpose + +This document consolidates **all evidence** for the ISMS in one place. The individual policies do not contain evidence lists but refer to this ({{LINK:NACHWEISREGISTER}}). Registers with ongoing records (asset inventory, risk register, supplier/NDA register, awareness evidence, record of processing activities) are maintained in **{{TOOL_NAME}}**; this register refers to them. + +The fine-grained mapping of evidence ↔ individual MUST/SHOULD requirement is done via `mapping.json` (hidden anchors `REQ`/`IMPL`) and is not visible in reading mode. From this, the tool generates an evidence link per requirement. + +## Evidence overview + +| # | Policy | Evidence | Source | Responsible | Cycle | +|---|-----------|----------|--------|----------------|--------| +| 1 | {{LINK:L00}} | Approved, versioned IS policy incl. communication record | Doc | {{ROLE_MANAGEMENT}} | {{REVIEW_CYCLE}} | +| 2 | {{LINK:R01}} | ISMS scope, role/responsibility matrix, management review | Tool/Doc | {{ROLE_ISB}} | annually | +| 3 | {{LINK:R02}} | Asset inventory & classification matrix; list of approved hardware/software | Tool | {{ROLE_IT_LEAD}} | ongoing | +| 4 | {{LINK:R03}} | Risk register & treatment plan; internal/independent review reports | Tool/Doc | {{ROLE_ISB}} | ≤ annually | +| 5 | {{LINK:R04}} | Incident records; crisis/emergency plan; recovery tests | Tool/Doc | {{ROLE_ISB}} | ongoing | +| 6 | {{LINK:R05}} | Confidentiality obligations; training/awareness evidence | Tool | {{ROLE_HR_LEAD}} | upon joining / annually | +| 7 | {{LINK:R06}} | Rule & approvals for mobile working / mobile devices | Doc/Tool | {{ROLE_ISB}} | ongoing | +| 8 | {{LINK:R07}} | Access concept, zone plan, access logs | Doc | {{ROLE_IT_LEAD}} | ongoing | +| 9 | {{LINK:R08}} | Authorisation concept & recertification evidence | Tool | {{ROLE_IT_LEAD}} | ≤ annually | +| 10 | {{LINK:R09}} | Cryptography concept, key/certificate management | Doc | {{ROLE_IT_LEAD}} | ongoing | +| 11 | {{LINK:R10}} | Change/patch/vulnerability reports, malware status, logging, backup/recovery tests | Tool/rec. | {{ROLE_IT_LEAD}} | ongoing | +| 12 | {{LINK:R11}} | Security requirements procurement/development; deletion evidence | Doc/rec. | {{ROLE_IT_LEAD}} | ongoing | +| 13 | {{LINK:R12}} | Approval list for cloud/AI services, segregation/data-flow evidence | Tool/Doc | {{ROLE_ISB}} | ongoing | +| 14 | {{LINK:R13}} | Supplier register, NDAs, delineation of responsibilities | Tool | {{ROLE_ISB}} | ongoing | +| 15 | {{LINK:R14}} | Compliance/legal register; record of processing activities | Tool | {{ROLE_DPO}} | ≤ annually | +| 16 | {{LINK:VA-22}} | Metrics sheet with targets, owners and measured values per period | Tool | {{ROLE_ISB}} | {{MGMT_REVIEW_CYCLE}} | +| 17 | {{LINK:VA-22}} | Management review minutes with inputs, decisions and due dates | Tool/Doc | {{ROLE_MANAGEMENT}} | {{MGMT_REVIEW_CYCLE}} | +| 18 | {{LINK:VA-21}} | Action register: nonconformities, root cause analysis, effectiveness review | Tool | {{ROLE_ISB}} | ongoing | +| 19 | {{LINK:R03}} | Statement of Applicability with justification, origin and implementation status | Tool/Doc | {{ROLE_ISB}} | {{RISK_REVIEW_CYCLE}} | +| 20 | {{LINK:L00}} | Read receipts of staff per approved policy version | Tool | {{ROLE_ISB}} | {{POLICY_REVIEW_CYCLE}} | + +> **Wizard note:** Rows with source `Tool` are not generated as a document but link to the record in {{TOOL_NAME}}. Conditional evidence is shown/hidden based on the feature flags (e.g. row 13 only with flag `FLAG_CLOUD_USED` / `FLAG_AI_USED`, row 10 only with flag `FLAG_CRYPTO_PKI`). + +## Related documents + +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Information security policy: {{LINK:L00}} diff --git a/seed/isms-vorlagenpaket-v2-en/Statement-of-Applicability-ISO.md b/seed/isms-vorlagenpaket-v2-en/Statement-of-Applicability-ISO.md new file mode 100644 index 0000000..faae0ef --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/Statement-of-Applicability-ISO.md @@ -0,0 +1,135 @@ +# Statement of Applicability + +| Document information | Value | +|-----------------------|------| +| Document type | Statement of Applicability | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + +## Purpose + +For each control of Annex A of ISO/IEC 27001:2022 this statement records whether it is applicable, why it was included or excluded, what it derives from and how far it is implemented (ISO/IEC 27001:2022, 6.1.3 d). It is updated with every risk assessment ({{RISK_REVIEW_CYCLE}}) and approved by {{ROLE_MANAGEMENT}}. The procedure is set out in {{LINK:R03}}. + +**Columns:** *Applicable* = yes/no · *Justification* = reason for inclusion or exclusion · *Origin* = risk ID, legal or contractual requirement · *Status* = implemented / partial / planned · *Evidence* = reference into the evidence register ({{LINK:NACHWEISREGISTER}}). + +## A.5 Organisational controls (37 controls) + +| Control | Title | Applicable | Justification | Origin | Status | Policy | Procedure | Evidence | +|---|---|:--:|---|---|---|---|---|---| +| A.5.1 | Policies for information security | yes | Determined as necessary by the risk treatment. | | | {{LINK:L00}} | - | | +| A.5.2 | Information security roles and responsibilities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R01}} | - | | +| A.5.3 | Segregation of duties | yes | Determined as necessary by the risk treatment. | | | {{LINK:R01}} | - | | +| A.5.4 | Management responsibilities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R01}} | - | | +| A.5.5 | Contact with authorities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R01}} | - | | +| A.5.6 | Contact with special interest groups | yes | Determined as necessary by the risk treatment. | | | {{LINK:R01}} | - | | +| A.5.7 | Threat intelligence | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.5.8 | Information security in project management | yes | Determined as necessary by the risk treatment. | | | {{LINK:R01}} | VA-19 | | +| A.5.9 | Inventory of information and other associated assets | yes | Determined as necessary by the risk treatment. | | | {{LINK:R02}} | VA-08 | | +| A.5.10 | Acceptable use of information and other associated assets | yes | Determined as necessary by the risk treatment. | | | {{LINK:R02}} | VA-08 | | +| A.5.11 | Return of assets | yes | Determined as necessary by the risk treatment. | | | {{LINK:R11}} | VA-08 | | +| A.5.12 | Classification of information | yes | Determined as necessary by the risk treatment. | | | {{LINK:R02}} | VA-08 | | +| A.5.13 | Labelling of information | yes | Determined as necessary by the risk treatment. | | | {{LINK:R02}} | VA-08 | | +| A.5.14 | Information transfer | yes | Determined as necessary by the risk treatment. | | | {{LINK:R09}} | - | | +| A.5.15 | Access control | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.5.16 | Identity management | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.5.17 | Authentication information | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.5.18 | Access rights | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.5.19 | Information security in supplier relationships | yes | Determined as necessary by the risk treatment. | | | {{LINK:R13}} | VA-10 | | +| A.5.20 | Addressing information security within supplier agreements | yes | Determined as necessary by the risk treatment. | | | {{LINK:R13}} | VA-10 | | +| A.5.21 | Managing information security in the ICT supply chain | yes | Determined as necessary by the risk treatment. | | | {{LINK:R13}} | VA-10 | | +| A.5.22 | Monitoring, review and change management of supplier services | yes | Determined as necessary by the risk treatment. | | | {{LINK:R13}} | VA-10 | | +| A.5.23 | Information security for use of cloud services | {{#if FLAG_CLOUD_USED}}yes{{/if}}{{#unless FLAG_CLOUD_USED}}no{{/unless}} | {{#if FLAG_CLOUD_USED}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_CLOUD_USED}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R12}} | VA-11 | | +| A.5.24 | Information security incident management planning and preparation | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-01 | | +| A.5.25 | Assessment and decision on information security events | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-01 | | +| A.5.26 | Response to information security incidents | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-01 | | +| A.5.27 | Learning from information security incidents | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-01 | | +| A.5.28 | Collection of evidence | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-01 | | +| A.5.29 | Information security during disruption | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-02 | | +| A.5.30 | ICT readiness for business continuity | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-02 | | +| A.5.31 | Legal, statutory, regulatory and contractual requirements | yes | Determined as necessary by the risk treatment. | | | {{LINK:R14}} | VA-18 | | +| A.5.32 | Intellectual property rights | yes | Determined as necessary by the risk treatment. | | | {{LINK:R14}} | VA-18 | | +| A.5.33 | Protection of records | yes | Determined as necessary by the risk treatment. | | | {{LINK:R14}} | VA-18 | | +| A.5.34 | Privacy and protection of PII | {{#if FLAG_PERSONAL_DATA}}yes{{/if}}{{#unless FLAG_PERSONAL_DATA}}no{{/unless}} | {{#if FLAG_PERSONAL_DATA}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_PERSONAL_DATA}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R14}} | VA-18 | | +| A.5.35 | Independent review of information security | yes | Determined as necessary by the risk treatment. | | | {{LINK:R03}} | VA-15 | | +| A.5.36 | Compliance with policies, rules and standards for information security | yes | Determined as necessary by the risk treatment. | | | {{LINK:R03}} | VA-15 | | +| A.5.37 | Documented operating procedures | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | + +## A.6 People controls (8 controls) + +| Control | Title | Applicable | Justification | Origin | Status | Policy | Procedure | Evidence | +|---|---|:--:|---|---|---|---|---|---| +| A.6.1 | Screening | yes | Determined as necessary by the risk treatment. | | | {{LINK:R05}} | VA-14 | | +| A.6.2 | Terms and conditions of employment | yes | Determined as necessary by the risk treatment. | | | {{LINK:R05}} | VA-14 | | +| A.6.3 | Information security awareness, education and training | yes | Determined as necessary by the risk treatment. | | | {{LINK:R05}} | VA-12 | | +| A.6.4 | Disciplinary process | yes | Determined as necessary by the risk treatment. | | | {{LINK:R05}} | - | | +| A.6.5 | Responsibilities after termination or change of employment | yes | Determined as necessary by the risk treatment. | | | {{LINK:R05}} | VA-14 | | +| A.6.6 | Confidentiality or non-disclosure agreements | yes | Determined as necessary by the risk treatment. | | | {{LINK:R05}} | VA-14 | | +| A.6.7 | Remote working | {{#if FLAG_MOBILE_WORK}}yes{{/if}}{{#unless FLAG_MOBILE_WORK}}no{{/unless}} | {{#if FLAG_MOBILE_WORK}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_MOBILE_WORK}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R06}} | - | | +| A.6.8 | Information security event reporting | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-01 | | + +## A.7 Physical controls (14 controls) + +| Control | Title | Applicable | Justification | Origin | Status | Policy | Procedure | Evidence | +|---|---|:--:|---|---|---|---|---|---| +| A.7.1 | Physical security perimeters | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.2 | Physical entry | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.3 | Securing offices, rooms and facilities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.4 | Physical security monitoring | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.5 | Protecting against physical and environmental threats | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.6 | Working in secure areas | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.7 | Clear desk and clear screen | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.8 | Equipment siting and protection | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.9 | Security of assets off-premises | {{#if FLAG_MOBILE_DEVICES}}yes{{/if}}{{#unless FLAG_MOBILE_DEVICES}}no{{/unless}} | {{#if FLAG_MOBILE_DEVICES}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_MOBILE_DEVICES}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R06}} | - | | +| A.7.10 | Storage media | yes | Determined as necessary by the risk treatment. | | | {{LINK:R06}} | VA-08 | | +| A.7.11 | Supporting utilities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.12 | Cabling security | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-17 | | +| A.7.13 | Equipment maintenance | yes | Determined as necessary by the risk treatment. | | | {{LINK:R07}} | VA-04 | | +| A.7.14 | Secure disposal or re-use of equipment | yes | Determined as necessary by the risk treatment. | | | {{LINK:R11}} | VA-08 | | + +## A.8 Technological controls (34 controls) + +| Control | Title | Applicable | Justification | Origin | Status | Policy | Procedure | Evidence | +|---|---|:--:|---|---|---|---|---|---| +| A.8.1 | User endpoint devices | yes | Determined as necessary by the risk treatment. | | | {{LINK:R06}} | - | | +| A.8.2 | Privileged access rights | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.8.3 | Information access restriction | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.8.4 | Access to source code | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.5 | Secure authentication | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.8.6 | Capacity management | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.8.7 | Protection against malware | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.8.8 | Management of technical vulnerabilities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-06 | | +| A.8.9 | Configuration management | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-04 | | +| A.8.10 | Information deletion | yes | Determined as necessary by the risk treatment. | | | {{LINK:R11}} | VA-08 | | +| A.8.11 | Data masking | {{#if FLAG_PERSONAL_DATA}}yes{{/if}}{{#unless FLAG_PERSONAL_DATA}}no{{/unless}} | {{#if FLAG_PERSONAL_DATA}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_PERSONAL_DATA}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R02}} | - | | +| A.8.12 | Data leakage prevention | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.8.13 | Information backup | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-05 | | +| A.8.14 | Redundancy of information processing facilities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R04}} | VA-02 | | +| A.8.15 | Logging | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-13 | | +| A.8.16 | Monitoring activities | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-13 | | +| A.8.17 | Clock synchronisation | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-13 | | +| A.8.18 | Use of privileged utility programs | yes | Determined as necessary by the risk treatment. | | | {{LINK:R08}} | VA-03 | | +| A.8.19 | Installation of software on operational systems | yes | Determined as necessary by the risk treatment. | | | {{LINK:R02}} | VA-04 | | +| A.8.20 | Networks security | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.8.21 | Security of network services | yes | Determined as necessary by the risk treatment. | | | {{LINK:R11}} | - | | +| A.8.22 | Segregation of networks | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.8.23 | Web filtering | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | - | | +| A.8.24 | Use of cryptography | yes | Determined as necessary by the risk treatment. | | | {{LINK:R09}} | VA-07 | | +| A.8.25 | Secure development life cycle | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.26 | Application security requirements | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.27 | Secure system architecture and engineering principles | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.28 | Secure coding | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.29 | Security testing in development and acceptance | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.30 | Outsourced development | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.31 | Separation of development, test and production environments | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R10}} | VA-16 | | +| A.8.32 | Change management | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-04 | | +| A.8.33 | Test information | {{#if FLAG_DEV_INHOUSE}}yes{{/if}}{{#unless FLAG_DEV_INHOUSE}}no{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Determined as necessary by the risk treatment.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Not applicable - enter justification.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.34 | Protection of information systems during audit testing | yes | Determined as necessary by the risk treatment. | | | {{LINK:R10}} | VA-15 | | + +## Management system requirements (clauses 4-10) + +The requirements of clauses 4 to 10 are not subject to the Statement of Applicability; they apply directly. Their allocation to the policies is held in `mapping-iso.json`. diff --git a/seed/isms-vorlagenpaket-v2-en/Technische-Sicherheits-Baseline.md b/seed/isms-vorlagenpaket-v2-en/Technische-Sicherheits-Baseline.md new file mode 100644 index 0000000..3e7319e --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/Technische-Sicherheits-Baseline.md @@ -0,0 +1,113 @@ +# Technical Security Baseline + +| Document information | Value | +|-----------------------|------| +| Document type | Requirements document (baseline) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + +## Purpose + +This document defines the **concrete technical minimum parameters** of information security. It is the central point of maintenance for all measurable values (password lengths, deadlines, procedures). For exact values, the policies R01–R14 refer to the **baseline IDs** assigned here (e.g. `BL-IAM-01`) and repeat the key statement concretely in the respective implementation text. + +Changes to parameters are made exclusively here and are approved by {{ROLE_ISB}}. The values are stored as adjustable defaults (variables); they correspond to the state of the art (guided, among others, by BSI IT-Grundschutz and current NIST recommendations). + +## 1. Identity and access management + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-IAM-01 | Password requirements | Minimum length {{PW_MIN_LENGTH}} characters; {{PW_COMPLEXITY}}; check against known/compromised passwords; {{PW_ROTATION}} | +| BL-IAM-02 | Multi-factor authentication (MFA) | Mandatory for {{MFA_SCOPE}} | +| BL-IAM-03 | Session management | Automatic lock upon inactivity: {{SESSION_TIMEOUT}} | +| BL-IAM-04 | Account lockout | {{ACCOUNT_LOCKOUT}} | +| BL-IAM-05 | Recertification of authorisations | {{RECERT_FREQ}}; privileged rights additionally on an ad-hoc basis | +| BL-IAM-06 | Privileged/technical accounts | Separate management, individual assignment, enhanced logging; management via the central directory ({{TOOL_IAM}}) | +| BL-IAM-07 | IAM documentation location | Requests/approvals/blockings in {{TOOL_TICKET}}; account management in the central directory ({{TOOL_IAM}}) | + +## 2. Cryptography and transmission + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-CRY-01 | Transport encryption | At least {{TLS_MIN}}; insecure protocols deactivated | +| BL-CRY-02 | Permissible algorithms/key lengths | {{CRYPTO_ALGO}} | +| BL-CRY-03 | Data media encryption | Full encryption of mobile devices and data media (AES-256) | +| BL-CRY-04 | Email/file exchange | Encryption of content requiring protection; secure exchange paths prescribed | +| BL-CRY-05 | Key management | Defined lifecycle (generation, distribution, storage, revocation, destruction){{#if FLAG_CRYPTO_PKI}}; PKI/certificate management established{{/if}} | + +## 3. Operational security + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-OPS-01 | Patch SLA | Critical: {{PATCH_SLA_CRIT}}; high: {{PATCH_SLA_HIGH}}; standard: {{PATCH_SLA_STD}} | +| BL-OPS-02 | Vulnerability scanning | {{VULN_SCAN_FREQ}}; tracking in {{TOOL_TICKET}} | +| BL-OPS-03 | Malware protection | {{TECH_MALWARE}} on all endpoints/servers; signature/engine update {{MALWARE_UPDATE}} | +| BL-OPS-04 | Logging & retention | Central logging ({{TECH_SIEM}}); retention {{LOG_RETENTION}}; tamper-protected | +| BL-OPS-05 | Data backup | Scheme {{BACKUP_SCHEME}} via {{TECH_BACKUP}}; retention {{BACKUP_RETENTION}} | +| BL-OPS-06 | Recovery tests | {{BACKUP_TEST_FREQ}}; result documented | +| BL-OPS-07 | System hardening | Hardening requirements (e.g. CIS benchmarks) for standard systems | +| BL-OPS-08 | Technical review / penetration test | {{PENTEST_FREQ}} or risk-oriented | +| BL-OPS-09 | Change management | Request/assessment/test/approval/documentation in {{TOOL_TICKET}} | +{{#if FLAG_FW_ISO27001}} +| BL-OPS-10 | Time synchronisation | System clocks of all logging systems synchronised to {{NTP_SOURCES}}; deviations are monitored | +| BL-OPS-11 | Capacity management | Utilisation (compute, memory, bandwidth, licences) monitored {{CAPACITY_REVIEW_FREQ}}; thresholds raise an alert | +| BL-OPS-12 | Protection against data leakage | Measures against unauthorised outflow of protected information for {{DLP_SCOPE}} | +{{/if}} + +## 4. Network security + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-NET-01 | Segmentation | Separation according to protection need; {{#if FLAG_OT_USED}}production/OT networks separated and specially secured; {{/if}}guest/external networks isolated | +| BL-NET-02 | Perimeter & remote access | Firewall with default deny; remote access only via {{TECH_VPN}} with MFA (BL-IAM-02) | +{{#if FLAG_FW_ISO27001}} +| BL-NET-03 | Web filtering | Access to external web content filtered (categories, known malicious sites); exceptions documented and time-limited | +{{/if}} + +## 5. Endpoint and mobile use + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-EP-01 | Device management | Management via {{TECH_MDM}}; only approved devices | +| BL-EP-02 | Device encryption/remote wipe | Full encryption (BL-CRY-03); blocking/wiping upon loss via {{TECH_MDM}} | +| BL-EP-03 | Removable media | Only encrypted and approved; use controlled | + +## 6. Physical security + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-PHY-01 | Security zones | Defined zones; access on a needs-oriented basis, documented, revoked when no longer needed | +| BL-PHY-02 | Access logging | Logging for areas requiring protection; visitors registered and escorted | +{{#if FLAG_FW_ISO27001}} +| BL-PHY-03 | Environmental protection and utilities | Early fire detection, protection against water, temperature/humidity monitoring in technical rooms; uninterruptible power for critical systems, tested regularly | +| BL-PHY-04 | Clear desk and screen lock | Protected documents and media locked away when unattended; automatic screen lock after {{SESSION_TIMEOUT}} | +{{/if}} + +## 7. Personnel and suppliers + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-HR-01 | Awareness/training | Upon joining and thereafter at least {{REVIEW_CYCLE}}; evidence in {{TOOL_NAME}} | +| BL-SUP-01 | Supplier risk classes | Classification according to protection need and access; verification of compliance (evidence/TISAX) | +| BL-DEL-01 | Secure deletion | Deletion/destruction appropriate to the protection need (e.g. according to recognised standards); deletion evidence | + +## 8. Governance and projects + +| ID | Parameter | Requirement | +|----|-----------|---------| +| BL-GOV-01 | Audit/review cycle | Internal review {{REVIEW_CYCLE}}; independent review/assessment at least every 3 years or after fundamental changes | +| BL-PROJ-01 | Project classification criteria | Documented catalogue of criteria for the IS classification of projects (triggers/thresholds for ISO involvement) | +{{#if FLAG_FW_ISO27001}} +| BL-GOV-02 | Management review | Top management reviews the ISMS {{MGMT_REVIEW_CYCLE}} against a fixed agenda; decisions with owner and due date | +| BL-GOV-03 | Document control | Review cycle of the policy and thematic policies {{POLICY_REVIEW_CYCLE}}; four-eyes approval; retention of superseded versions {{RECORDS_RETENTION}} | +{{/if}} + +## Change history + +| Version | Date | Author | Change | +|---------|-------|-------|----------| +| {{DOC_VERSION}} | {{DOC_DATE}} | {{ROLE_IT_LEAD}} | Creation | diff --git a/seed/isms-vorlagenpaket-v2-en/mapping-iso.json b/seed/isms-vorlagenpaket-v2-en/mapping-iso.json new file mode 100644 index 0000000..33543cc --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/mapping-iso.json @@ -0,0 +1,2219 @@ +{ + "meta": { + "paket": "ISMS-Vorlagenpaket v2 — Framework-Mapping ISO/IEC 27001:2022", + "standard": "ISO/IEC 27001:2022 (Kap. 4-10 + Anhang A)", + "framework": "ISO_27001", + "version": "2.1", + "bibliothek": "gemeinsam mit dem VDA-ISA-Mapping (mapping.json) — ein Dokumentensatz, zwei Mappings", + "hinweis": "Anforderungstexte sind eigene Paraphrasen (keine woertlichen Normzitate); die Referenzen sind exakt zum Nachschlagen. Der Umsetzungstext wird ueber impl_anchor aus dem jeweiligen Richtlinienabschnitt aufgeloest und ist mit dem VDA-ISA-Mapping geteilt.", + "coverage": "27 Klausel-Anforderungen (Kap. 4-10) + 93 Anhang-A-Controls = 120 Eintraege" + }, + "anforderungen": [ + { + "id": "4.1-1", + "policy": "R01", + "control": "4.1", + "kind": "clause", + "title": "Understanding the organisation and its context", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.1-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "Internal and external issues that affect the ability to achieve the ISMS objectives are determined and kept up to date.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2-1", + "policy": "R01", + "control": "4.2", + "kind": "clause", + "title": "Needs of interested parties", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.2-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "The interested parties relevant to the ISMS and their information security requirements are determined.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.3-1", + "policy": "R01", + "control": "4.3", + "kind": "clause", + "title": "Scope of the ISMS", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.3-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "The scope of the ISMS is determined considering the issues, requirements and interfaces, and maintained as documented information.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.4-1", + "policy": "R01", + "control": "4.4", + "kind": "clause", + "title": "Information security management system", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.4-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "An ISMS is established, implemented, maintained and continually improved.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1-1", + "policy": "R01", + "control": "5.1", + "kind": "clause", + "title": "Leadership and commitment", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 5.1-1", + "impl_anchor": "IMPL 1.2.1", + "requirement": "Top management demonstrates leadership and commitment with respect to the ISMS.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2-1", + "policy": "L00", + "control": "5.2", + "kind": "clause", + "title": "Information security policy", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 5.2-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "An information security policy is established that fits the organisation, sets objectives, commits to meeting requirements and to continual improvement, and is communicated and available.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.3-1", + "policy": "R01", + "control": "5.3", + "kind": "clause", + "title": "Roles, responsibilities and authorities", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 5.3-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Responsibilities and authorities for security-relevant roles are assigned and communicated.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-1", + "policy": "R03", + "control": "6.1.1", + "kind": "clause", + "title": "Actions to address risks and opportunities", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.1.1-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "When planning the ISMS, risks and opportunities that need to be addressed are determined.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "6.1.2-1", + "policy": "R03", + "control": "6.1.2", + "kind": "clause", + "title": "Information security risk assessment", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.1.2-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "A risk assessment process with defined criteria is established and applied so that it is repeatable and produces comparable results.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "6.1.3-1", + "policy": "R03", + "control": "6.1.3", + "kind": "clause", + "title": "Information security risk treatment", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.1.3-1", + "impl_anchor": "IMPL ISO-SOA", + "requirement": "A risk treatment process is defined; necessary controls are determined and compared against Annex A in a Statement of Applicability.", + "link": "{{LINK:R03#ISO-SOA}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "6.2-1", + "policy": "L00", + "control": "6.2", + "kind": "clause", + "title": "Information security objectives and planning", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.2-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "Information security objectives are established for relevant functions and levels, and their achievement is planned.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.3-1", + "policy": "R01", + "control": "6.3", + "kind": "clause", + "title": "Planning of changes", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.3-1", + "impl_anchor": "IMPL ISO-MS-CHANGE", + "requirement": "Changes to the ISMS are carried out in a planned manner.", + "link": "{{LINK:R01#ISO-MS-CHANGE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.1-1", + "policy": "R01", + "control": "7.1", + "kind": "clause", + "title": "Resources", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.1-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "The resources needed for the ISMS are determined and provided.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.2-1", + "policy": "R05", + "control": "7.2", + "kind": "clause", + "title": "Competence", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.2-1", + "impl_anchor": "IMPL 2.1.1", + "requirement": "The necessary competence is determined and ensured; corresponding evidence is retained.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.3-1", + "policy": "R05", + "control": "7.3", + "kind": "clause", + "title": "Awareness", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.3-1", + "impl_anchor": "IMPL 2.1.3", + "requirement": "Persons under the organisation's control are aware of the policy, their contribution and the consequences of non-conformance.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "7.4-1", + "policy": "L00", + "control": "7.4", + "kind": "clause", + "title": "Communication", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.4-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "The internal and external communications relevant to the ISMS are determined.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.5.1-1", + "policy": "R01", + "control": "7.5.1", + "kind": "clause", + "title": "Documented information — general", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.5.1-1", + "impl_anchor": "IMPL ISO-MS-DOKU", + "requirement": "The ISMS includes the documented information required by the standard and that determined as necessary.", + "link": "{{LINK:R01#ISO-MS-DOKU}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.5.2-1", + "policy": "R01", + "control": "7.5.2", + "kind": "clause", + "title": "Creating and updating", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.5.2-1", + "impl_anchor": "IMPL ISO-MS-DOKU", + "requirement": "When creating and updating documented information, identification, format and medium as well as review and approval are ensured.", + "link": "{{LINK:R01#ISO-MS-DOKU}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.5.3-1", + "policy": "R01", + "control": "7.5.3", + "kind": "clause", + "title": "Control of documented information", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.5.3-1", + "impl_anchor": "IMPL ISO-MS-DOKU", + "requirement": "Documented information is controlled: availability, protection, distribution, access, retention and change control.", + "link": "{{LINK:R01#ISO-MS-DOKU}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "8.1-1", + "policy": "R03", + "control": "8.1", + "kind": "clause", + "title": "Operational planning and control", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 8.1-1", + "impl_anchor": "IMPL ISO-MS-BETRIEB", + "requirement": "The processes needed to meet the requirements are planned, implemented and controlled; planned changes are controlled.", + "link": "{{LINK:R03#ISO-MS-BETRIEB}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "8.2-1", + "policy": "R03", + "control": "8.2", + "kind": "clause", + "title": "Information security risk assessment (performance)", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 8.2-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "Risk assessments are performed at planned intervals and upon significant change, and are documented.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "8.3-1", + "policy": "R03", + "control": "8.3", + "kind": "clause", + "title": "Information security risk treatment (performance)", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 8.3-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "The risk treatment plan is implemented and the results are documented.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "9.1-1", + "policy": "R03", + "control": "9.1", + "kind": "clause", + "title": "Monitoring, measurement, analysis and evaluation", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 9.1-1", + "impl_anchor": "IMPL ISO-MS-MESSUNG", + "requirement": "The information security performance and the effectiveness of the ISMS are monitored, measured, analysed and evaluated.", + "link": "{{LINK:R03#ISO-MS-MESSUNG}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-22" + ] + }, + { + "id": "9.2-1", + "policy": "R03", + "control": "9.2", + "kind": "clause", + "title": "Internal audit", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 9.2-1", + "impl_anchor": "IMPL 1.5.2", + "requirement": "Internal audits are conducted at planned intervals to verify conformity and effective implementation of the ISMS.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "9.3-1", + "policy": "R03", + "control": "9.3", + "kind": "clause", + "title": "Management review", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 9.3-1", + "impl_anchor": "IMPL ISO-MS-MGMTREVIEW", + "requirement": "Top management reviews the ISMS at planned intervals.", + "link": "{{LINK:R03#ISO-MS-MGMTREVIEW}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-22" + ] + }, + { + "id": "10.1-1", + "policy": "R03", + "control": "10.1", + "kind": "clause", + "title": "Continual improvement", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 10.1-1", + "impl_anchor": "IMPL ISO-MS-CAPA", + "requirement": "The suitability, adequacy and effectiveness of the ISMS are continually improved.", + "link": "{{LINK:R03#ISO-MS-CAPA}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-21" + ] + }, + { + "id": "10.2-1", + "policy": "R03", + "control": "10.2", + "kind": "clause", + "title": "Nonconformity and corrective action", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 10.2-1", + "impl_anchor": "IMPL ISO-MS-CAPA", + "requirement": "In the event of nonconformity, corrections are made and corrective actions are taken to eliminate the causes.", + "link": "{{LINK:R03#ISO-MS-CAPA}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-21" + ] + }, + { + "id": "A.5.1-1", + "policy": "L00", + "control": "A.5.1", + "kind": "control", + "title": "Policies for information security", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.1-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "The information security policy and topic-specific policies are defined, approved by management, published, communicated, acknowledged and reviewed at planned intervals.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.2-1", + "policy": "R01", + "control": "A.5.2", + "kind": "control", + "title": "Information security roles and responsibilities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.2-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Information security roles and responsibilities are defined and allocated.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.3-1", + "policy": "R01", + "control": "A.5.3", + "kind": "control", + "title": "Segregation of duties", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.3-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Conflicting duties and areas of responsibility are segregated to reduce unauthorised or unintentional modification and misuse.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.4-1", + "policy": "R01", + "control": "A.5.4", + "kind": "control", + "title": "Management responsibilities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.4-1", + "impl_anchor": "IMPL 1.2.1", + "requirement": "Management requires all personnel to apply information security in accordance with the established requirements.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.5-1", + "policy": "R01", + "control": "A.5.5", + "kind": "control", + "title": "Contact with authorities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.5-1", + "impl_anchor": "IMPL ISO-KONTAKTE", + "requirement": "Appropriate contacts with relevant authorities are established and maintained.", + "link": "{{LINK:R01#ISO-KONTAKTE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.6-1", + "policy": "R01", + "control": "A.5.6", + "kind": "control", + "title": "Contact with special interest groups", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.6-1", + "impl_anchor": "IMPL ISO-KONTAKTE", + "requirement": "Appropriate contacts with special interest groups, professional forums and security associations are maintained.", + "link": "{{LINK:R01#ISO-KONTAKTE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.7-1", + "policy": "R10", + "control": "A.5.7", + "kind": "control", + "title": "Threat intelligence", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.7-1", + "impl_anchor": "IMPL ISO-THREATINTEL", + "requirement": "Information on threats is collected and analysed to produce and use threat intelligence.", + "link": "{{LINK:R10#ISO-THREATINTEL}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.8-1", + "policy": "R01", + "control": "A.5.8", + "kind": "control", + "title": "Information security in project management", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.8-1", + "impl_anchor": "IMPL 1.2.3", + "requirement": "Information security is integrated into project management.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "A.5.9-1", + "policy": "R02", + "control": "A.5.9", + "kind": "control", + "title": "Inventory of information and other associated assets", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.9-1", + "impl_anchor": "IMPL 1.3.1", + "requirement": "An inventory of information and associated assets, including owners, is established and maintained.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.10-1", + "policy": "R02", + "control": "A.5.10", + "kind": "control", + "title": "Acceptable use of information and other associated assets", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.10-1", + "impl_anchor": "IMPL 1.3.3", + "requirement": "Rules for the acceptable use and handling of information and assets are defined, documented and implemented.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.11-1", + "policy": "R11", + "control": "A.5.11", + "kind": "control", + "title": "Return of assets", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.11-1", + "impl_anchor": "IMPL 5.3.3", + "requirement": "Personnel and external users return all assets in their possession upon termination of employment or contract.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.12-1", + "policy": "R02", + "control": "A.5.12", + "kind": "control", + "title": "Classification of information", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.12-1", + "impl_anchor": "IMPL 1.3.2", + "requirement": "Information is classified according to its protection needs (confidentiality, integrity, availability).", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.13-1", + "policy": "R02", + "control": "A.5.13", + "kind": "control", + "title": "Labelling of information", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.13-1", + "impl_anchor": "IMPL 1.3.2", + "requirement": "Procedures for labelling information in accordance with the classification scheme are developed and implemented.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.14-1", + "policy": "R09", + "control": "A.5.14", + "kind": "control", + "title": "Information transfer", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.14-1", + "impl_anchor": "IMPL 5.1.2", + "requirement": "Rules, procedures and agreements for the secure transfer of information are established for all transfer channels in use.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.15-1", + "policy": "R08", + "control": "A.5.15", + "kind": "control", + "title": "Access control", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.15-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Rules to control physical and logical access to information and assets are established and implemented on the basis of business and information security requirements.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.16-1", + "policy": "R08", + "control": "A.5.16", + "kind": "control", + "title": "Identity management", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.16-1", + "impl_anchor": "IMPL 4.1.1", + "requirement": "The full life cycle of identities is managed.", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.17-1", + "policy": "R08", + "control": "A.5.17", + "kind": "control", + "title": "Authentication information", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.17-1", + "impl_anchor": "IMPL 4.1.3", + "requirement": "Allocation and management of authentication information is controlled by a suitable management process.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.18-1", + "policy": "R08", + "control": "A.5.18", + "kind": "control", + "title": "Access rights", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.18-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Access rights are provisioned, reviewed, modified and removed in accordance with the access control policy.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.19-1", + "policy": "R13", + "control": "A.5.19", + "kind": "control", + "title": "Information security in supplier relationships", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.19-1", + "impl_anchor": "IMPL 6.1.1", + "requirement": "Processes to manage the information security risks arising from supplier relationships are defined and implemented.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.20-1", + "policy": "R13", + "control": "A.5.20", + "kind": "control", + "title": "Addressing information security within supplier agreements", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.20-1", + "impl_anchor": "IMPL 6.1.2", + "requirement": "Relevant information security requirements are agreed with each supplier and recorded contractually.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.21-1", + "policy": "R13", + "control": "A.5.21", + "kind": "control", + "title": "Managing information security in the ICT supply chain", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.21-1", + "impl_anchor": "IMPL 6.1.3", + "requirement": "Processes to manage information security risks in the ICT product and service supply chain are defined and implemented.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.22-1", + "policy": "R13", + "control": "A.5.22", + "kind": "control", + "title": "Monitoring, review and change management of supplier services", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.22-1", + "impl_anchor": "IMPL 6.1.1", + "requirement": "The information security of supplier services is monitored and reviewed regularly, and changes are managed.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.23-1", + "policy": "R12", + "control": "A.5.23", + "kind": "control", + "title": "Information security for use of cloud services", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_CLOUD_USED", + "req_anchor": "REQ A.5.23-1", + "impl_anchor": "IMPL 5.3.4", + "requirement": "Processes for acquisition, use, management and exit of cloud services are established in line with the information security requirements.", + "link": "{{LINK:R12#5.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "A.5.24-1", + "policy": "R04", + "control": "A.5.24", + "kind": "control", + "title": "Information security incident management planning and preparation", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.24-1", + "impl_anchor": "IMPL 1.6.1", + "requirement": "The management of information security incidents is planned and prepared (roles, processes, responsibilities).", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.25-1", + "policy": "R04", + "control": "A.5.25", + "kind": "control", + "title": "Assessment and decision on information security events", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.25-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Information security events are assessed and a decision is taken whether they are to be categorised as incidents.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.26-1", + "policy": "R04", + "control": "A.5.26", + "kind": "control", + "title": "Response to information security incidents", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.26-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Information security incidents are responded to in accordance with documented procedures.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.27-1", + "policy": "R04", + "control": "A.5.27", + "kind": "control", + "title": "Learning from information security incidents", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.27-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Knowledge gained from information security incidents is used to strengthen the controls.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.28-1", + "policy": "R04", + "control": "A.5.28", + "kind": "control", + "title": "Collection of evidence", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.28-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Procedures for the identification, collection, acquisition and preservation of evidence relating to incidents are established and implemented.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.29-1", + "policy": "R04", + "control": "A.5.29", + "kind": "control", + "title": "Information security during disruption", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.29-1", + "impl_anchor": "IMPL 1.6.3", + "requirement": "The maintenance of information security during disruption is planned and implemented.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "A.5.30-1", + "policy": "R04", + "control": "A.5.30", + "kind": "control", + "title": "ICT readiness for business continuity", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.30-1", + "impl_anchor": "IMPL 5.2.8", + "requirement": "ICT readiness is planned, implemented and tested on the basis of the business continuity objectives and requirements.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "A.5.31-1", + "policy": "R14", + "control": "A.5.31", + "kind": "control", + "title": "Legal, statutory, regulatory and contractual requirements", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.31-1", + "impl_anchor": "IMPL 7.1.1", + "requirement": "Legal, statutory, regulatory and contractual information security requirements are identified, documented and kept up to date.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.32-1", + "policy": "R14", + "control": "A.5.32", + "kind": "control", + "title": "Intellectual property rights", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.32-1", + "impl_anchor": "IMPL 7.1.1", + "requirement": "Appropriate procedures to protect intellectual property rights are implemented.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.33-1", + "policy": "R14", + "control": "A.5.33", + "kind": "control", + "title": "Protection of records", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.33-1", + "impl_anchor": "IMPL 7.1.1", + "requirement": "Records are protected against loss, destruction, falsification, unauthorised access and unauthorised release.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.34-1", + "policy": "R14", + "control": "A.5.34", + "kind": "control", + "title": "Privacy and protection of PII", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_PERSONAL_DATA", + "req_anchor": "REQ A.5.34-1", + "impl_anchor": "IMPL 7.1.2", + "requirement": "Requirements for the protection of personally identifiable information are identified and met in accordance with applicable obligations.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.35-1", + "policy": "R03", + "control": "A.5.35", + "kind": "control", + "title": "Independent review of information security", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.35-1", + "impl_anchor": "IMPL 1.5.2", + "requirement": "The organisation's approach to managing information security is reviewed independently at planned intervals.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "A.5.36-1", + "policy": "R03", + "control": "A.5.36", + "kind": "control", + "title": "Compliance with policies, rules and standards for information security", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.36-1", + "impl_anchor": "IMPL 1.5.1", + "requirement": "Compliance with the information security policy, topic-specific policies, rules and standards is reviewed regularly.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "A.5.37-1", + "policy": "R10", + "control": "A.5.37", + "kind": "control", + "title": "Documented operating procedures", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.37-1", + "impl_anchor": "IMPL ISO-BETRIEBSABLAEUFE", + "requirement": "Operating procedures for information processing facilities are documented and made available to the personnel concerned.", + "link": "{{LINK:R10#ISO-BETRIEBSABLAEUFE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.6.1-1", + "policy": "R05", + "control": "A.6.1", + "kind": "control", + "title": "Screening", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.1-1", + "impl_anchor": "IMPL 2.1.1", + "requirement": "Background verification of candidates is carried out appropriately to the business requirements and in accordance with the law.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.2-1", + "policy": "R05", + "control": "A.6.2", + "kind": "control", + "title": "Terms and conditions of employment", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.2-1", + "impl_anchor": "IMPL 2.1.2", + "requirement": "The employment agreements state the responsibilities for information security.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.3-1", + "policy": "R05", + "control": "A.6.3", + "kind": "control", + "title": "Information security awareness, education and training", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.3-1", + "impl_anchor": "IMPL 2.1.3", + "requirement": "Personnel receive appropriate awareness, education and training as well as regular updates of the relevant policies.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "A.6.4-1", + "policy": "R05", + "control": "A.6.4", + "kind": "control", + "title": "Disciplinary process", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.4-1", + "impl_anchor": "IMPL ISO-DISZIPLIN", + "requirement": "A disciplinary process for information security violations is established and communicated.", + "link": "{{LINK:R05#ISO-DISZIPLIN}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.6.5-1", + "policy": "R05", + "control": "A.6.5", + "kind": "control", + "title": "Responsibilities after termination or change of employment", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.5-1", + "impl_anchor": "IMPL 2.1.2", + "requirement": "Continuing information security responsibilities after termination or change of employment are defined and enforced.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.6-1", + "policy": "R05", + "control": "A.6.6", + "kind": "control", + "title": "Confidentiality or non-disclosure agreements", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.6-1", + "impl_anchor": "IMPL 2.1.2", + "requirement": "Confidentiality or non-disclosure agreements are identified, documented and reviewed regularly.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.7-1", + "policy": "R06", + "control": "A.6.7", + "kind": "control", + "title": "Remote working", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_MOBILE_WORK", + "req_anchor": "REQ A.6.7-1", + "impl_anchor": "IMPL 2.1.4", + "requirement": "Security measures for working outside the organisation's premises are implemented.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.6.8-1", + "policy": "R04", + "control": "A.6.8", + "kind": "control", + "title": "Information security event reporting", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.8-1", + "impl_anchor": "IMPL 1.6.1", + "requirement": "A mechanism for the timely reporting of observed or suspected information security events is provided.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.7.1-1", + "policy": "R07", + "control": "A.7.1", + "kind": "control", + "title": "Physical security perimeters", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.1-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Security perimeters are defined and used to protect areas containing information and assets.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.2-1", + "policy": "R07", + "control": "A.7.2", + "kind": "control", + "title": "Physical entry", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.2-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Secure entry controls and entry points are established to restrict access to authorised persons.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.3-1", + "policy": "R07", + "control": "A.7.3", + "kind": "control", + "title": "Securing offices, rooms and facilities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.3-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Physical security for offices, rooms and facilities is designed and implemented.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.4-1", + "policy": "R07", + "control": "A.7.4", + "kind": "control", + "title": "Physical security monitoring", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.4-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Premises are continuously monitored for unauthorised physical access.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.5-1", + "policy": "R07", + "control": "A.7.5", + "kind": "control", + "title": "Protecting against physical and environmental threats", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.5-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Protection against physical and environmental threats is designed and implemented.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.6-1", + "policy": "R07", + "control": "A.7.6", + "kind": "control", + "title": "Working in secure areas", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.6-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Measures for working in secure areas are defined and implemented.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.7-1", + "policy": "R07", + "control": "A.7.7", + "kind": "control", + "title": "Clear desk and clear screen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.7-1", + "impl_anchor": "IMPL ISO-PHY-CLEARDESK", + "requirement": "Rules for a clear desk and locked screens are defined and implemented.", + "link": "{{LINK:R07#ISO-PHY-CLEARDESK}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.8-1", + "policy": "R07", + "control": "A.7.8", + "kind": "control", + "title": "Equipment siting and protection", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.8-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Equipment is sited securely and protected.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.9-1", + "policy": "R06", + "control": "A.7.9", + "kind": "control", + "title": "Security of assets off-premises", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_MOBILE_DEVICES", + "req_anchor": "REQ A.7.9-1", + "impl_anchor": "IMPL 3.1.4", + "requirement": "Assets used outside the premises are protected.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.7.10-1", + "policy": "R06", + "control": "A.7.10", + "kind": "control", + "title": "Storage media", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.10-1", + "impl_anchor": "IMPL 3.1.4", + "requirement": "Storage media are protected throughout their life cycle (acquisition, use, transport, disposal) in accordance with the classification scheme.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.7.11-1", + "policy": "R07", + "control": "A.7.11", + "kind": "control", + "title": "Supporting utilities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.11-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Facilities are protected against failure and disruption of supporting utilities such as power and air conditioning.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.12-1", + "policy": "R07", + "control": "A.7.12", + "kind": "control", + "title": "Cabling security", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.12-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Power and data cabling is protected against interception, interference and damage.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.13-1", + "policy": "R07", + "control": "A.7.13", + "kind": "control", + "title": "Equipment maintenance", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.13-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Equipment is maintained properly to ensure availability and integrity.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.7.14-1", + "policy": "R11", + "control": "A.7.14", + "kind": "control", + "title": "Secure disposal or re-use of equipment", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.14-1", + "impl_anchor": "IMPL 5.3.3", + "requirement": "Equipment containing storage media is securely sanitised before disposal or re-use.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.8.1-1", + "policy": "R06", + "control": "A.8.1", + "kind": "control", + "title": "User endpoint devices", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.1-1", + "impl_anchor": "IMPL 3.1.4", + "requirement": "Information stored on, processed by or accessible via user endpoint devices is protected.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.2-1", + "policy": "R08", + "control": "A.8.2", + "kind": "control", + "title": "Privileged access rights", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.2-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "The allocation and use of privileged access rights is restricted and closely managed.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.3-1", + "policy": "R08", + "control": "A.8.3", + "kind": "control", + "title": "Information access restriction", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.3-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Access to information and application functions is restricted in accordance with the access control policy.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.4-1", + "policy": "R11", + "control": "A.8.4", + "kind": "control", + "title": "Access to source code", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.4-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Read and write access to source code, development tools and software libraries is appropriately managed.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.5-1", + "policy": "R08", + "control": "A.8.5", + "kind": "control", + "title": "Secure authentication", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.5-1", + "impl_anchor": "IMPL 4.1.2", + "requirement": "Secure authentication technologies and procedures are used on the basis of the access restrictions and the access control policy.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.6-1", + "policy": "R10", + "control": "A.8.6", + "kind": "control", + "title": "Capacity management", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.6-1", + "impl_anchor": "IMPL ISO-KAPAZITAET", + "requirement": "Resources are monitored and capacity is adjusted to current and expected demand.", + "link": "{{LINK:R10#ISO-KAPAZITAET}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.7-1", + "policy": "R10", + "control": "A.8.7", + "kind": "control", + "title": "Protection against malware", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.7-1", + "impl_anchor": "IMPL 5.2.3", + "requirement": "Protection against malware is implemented and supported by appropriate user awareness.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.8-1", + "policy": "R10", + "control": "A.8.8", + "kind": "control", + "title": "Management of technical vulnerabilities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.8-1", + "impl_anchor": "IMPL 5.2.5", + "requirement": "Information on technical vulnerabilities is obtained, exposure is evaluated and appropriate measures are taken.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-06" + ] + }, + { + "id": "A.8.9-1", + "policy": "R10", + "control": "A.8.9", + "kind": "control", + "title": "Configuration management", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.9-1", + "impl_anchor": "IMPL 5.2.1", + "requirement": "Configurations of hardware, software, services and networks are established, documented, implemented, monitored and reviewed.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.8.10-1", + "policy": "R11", + "control": "A.8.10", + "kind": "control", + "title": "Information deletion", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.10-1", + "impl_anchor": "IMPL 5.3.3", + "requirement": "Information stored in systems and on media is deleted when no longer required.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.8.11-1", + "policy": "R02", + "control": "A.8.11", + "kind": "control", + "title": "Data masking", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_PERSONAL_DATA", + "req_anchor": "REQ A.8.11-1", + "impl_anchor": "IMPL ISO-MASKIERUNG", + "requirement": "Data masking is applied in accordance with the access control and privacy requirements.", + "link": "{{LINK:R02#ISO-MASKIERUNG}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.12-1", + "policy": "R10", + "control": "A.8.12", + "kind": "control", + "title": "Data leakage prevention", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.12-1", + "impl_anchor": "IMPL ISO-DLP", + "requirement": "Measures to prevent data leakage are applied to systems, networks and devices that process sensitive information.", + "link": "{{LINK:R10#ISO-DLP}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.13-1", + "policy": "R10", + "control": "A.8.13", + "kind": "control", + "title": "Information backup", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.13-1", + "impl_anchor": "IMPL 5.2.9", + "requirement": "Backup copies of information, software and systems are created in accordance with the backup concept and tested regularly.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "A.8.14-1", + "policy": "R04", + "control": "A.8.14", + "kind": "control", + "title": "Redundancy of information processing facilities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.14-1", + "impl_anchor": "IMPL 5.2.8", + "requirement": "Information processing facilities are implemented with sufficient redundancy to meet the availability requirements.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "A.8.15-1", + "policy": "R10", + "control": "A.8.15", + "kind": "control", + "title": "Logging", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.15-1", + "impl_anchor": "IMPL 5.2.4", + "requirement": "Logs of activities, exceptions, faults and events are produced, stored, protected and analysed.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "A.8.16-1", + "policy": "R10", + "control": "A.8.16", + "kind": "control", + "title": "Monitoring activities", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.16-1", + "impl_anchor": "IMPL 5.2.4", + "requirement": "Networks, systems and applications are monitored for anomalous behaviour and potential incidents are evaluated.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "A.8.17-1", + "policy": "R10", + "control": "A.8.17", + "kind": "control", + "title": "Clock synchronisation", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.17-1", + "impl_anchor": "IMPL ISO-ZEITSYNC", + "requirement": "System clocks are synchronised to approved time sources.", + "link": "{{LINK:R10#ISO-ZEITSYNC}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "A.8.18-1", + "policy": "R08", + "control": "A.8.18", + "kind": "control", + "title": "Use of privileged utility programs", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.18-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "The use of utility programs capable of overriding system and application controls is restricted and tightly controlled.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.19-1", + "policy": "R02", + "control": "A.8.19", + "kind": "control", + "title": "Installation of software on operational systems", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.19-1", + "impl_anchor": "IMPL 1.3.4", + "requirement": "Procedures and measures for securely managing software installation on operational systems are implemented.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.8.20-1", + "policy": "R10", + "control": "A.8.20", + "kind": "control", + "title": "Networks security", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.20-1", + "impl_anchor": "IMPL 5.2.7", + "requirement": "Networks and network devices are secured, managed and controlled to protect information.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.21-1", + "policy": "R11", + "control": "A.8.21", + "kind": "control", + "title": "Security of network services", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.21-1", + "impl_anchor": "IMPL 5.3.2", + "requirement": "Security mechanisms, service levels and requirements for network services are identified, implemented and monitored.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.22-1", + "policy": "R10", + "control": "A.8.22", + "kind": "control", + "title": "Segregation of networks", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.22-1", + "impl_anchor": "IMPL 5.2.7", + "requirement": "Groups of information services, users and systems are segregated in networks.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.23-1", + "policy": "R10", + "control": "A.8.23", + "kind": "control", + "title": "Web filtering", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.23-1", + "impl_anchor": "IMPL 5.2.3", + "requirement": "Access to external websites is managed to reduce exposure to malicious content.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.24-1", + "policy": "R09", + "control": "A.8.24", + "kind": "control", + "title": "Use of cryptography", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.24-1", + "impl_anchor": "IMPL 5.1.1", + "requirement": "Rules for the effective use of cryptography, including key management, are defined and implemented.", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "A.8.25-1", + "policy": "R11", + "control": "A.8.25", + "kind": "control", + "title": "Secure development life cycle", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.25-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Rules for a secure development life cycle of software and systems are established and applied.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.26-1", + "policy": "R11", + "control": "A.8.26", + "kind": "control", + "title": "Application security requirements", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.26-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Information security requirements are identified, specified and taken into account when developing or acquiring applications.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.27-1", + "policy": "R11", + "control": "A.8.27", + "kind": "control", + "title": "Secure system architecture and engineering principles", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.27-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Principles for engineering secure systems are established, documented and applied.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.28-1", + "policy": "R11", + "control": "A.8.28", + "kind": "control", + "title": "Secure coding", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.28-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Secure coding principles are applied to software development.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.29-1", + "policy": "R11", + "control": "A.8.29", + "kind": "control", + "title": "Security testing in development and acceptance", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.29-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Security testing is integrated into the development and acceptance process.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.30-1", + "policy": "R11", + "control": "A.8.30", + "kind": "control", + "title": "Outsourced development", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.30-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Outsourced system development is directed, monitored and reviewed.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.31-1", + "policy": "R10", + "control": "A.8.31", + "kind": "control", + "title": "Separation of development, test and production environments", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.31-1", + "impl_anchor": "IMPL 5.2.2", + "requirement": "Development, test and production environments are separated and protected.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.32-1", + "policy": "R10", + "control": "A.8.32", + "kind": "control", + "title": "Change management", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.32-1", + "impl_anchor": "IMPL 5.2.1", + "requirement": "Changes to information processing facilities and systems are subject to change management.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.8.33-1", + "policy": "R11", + "control": "A.8.33", + "kind": "control", + "title": "Test information", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.33-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Test information is selected, protected and managed with care.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.34-1", + "policy": "R10", + "control": "A.8.34", + "kind": "control", + "title": "Protection of information systems during audit testing", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.34-1", + "impl_anchor": "IMPL 5.2.6", + "requirement": "Audit tests and similar activities on operational systems are planned and agreed to avoid disruption.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + } + ] +} diff --git a/seed/isms-vorlagenpaket-v2-en/mapping.json b/seed/isms-vorlagenpaket-v2-en/mapping.json new file mode 100644 index 0000000..adb2144 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/mapping.json @@ -0,0 +1,5351 @@ +{ + "meta": { + "paket": "ISMS-Vorlagenpaket v2", + "standard": "VDA ISA 2027 (Information Security)", + "hinweis": "Anforderungen 1:1 aus ISA; Umsetzung gebuendelt je Control. is_isa=false = kundenspezifische Ergaenzung (z.B. KI).", + "isa_quelldubletten": [ + { + "control": "1.6.3", + "ebene": "high", + "doppelte_quellzeilen": 3, + "abgedeckt_durch": [ + "1.6.3-H1", + "1.6.3-H2", + "1.6.3-H5" + ], + "hinweis": "ISA wiederholt Krisenszenario-/Ressourcen-/Test-Zeilen mit/ohne Zusatz \"The following aspects are considered\"." + }, + { + "control": "5.2.9", + "ebene": "high", + "doppelte_quellzeilen": 1, + "abgedeckt_durch": [ + "5.2.9-H1" + ], + "hinweis": "ISA-Zeile \"Backup and recovery concepts exist\" ist redundant zum Must-Konzept und zu H1." + } + ], + "coverage": "316 eindeutige ISA-Zeilen; 4 Quelldubletten konsolidiert -> 312 eindeutige Anforderungen (100% inhaltliche Abdeckung). Plus 4 kundenspezifische KI-Anforderungen.", + "version": "2.1" + }, + "anforderungen": [ + { + "id": "1.1.1-M1", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M1", + "impl_anchor": "REQ 1.1.1-M1", + "condition": null, + "requirement": "The information security requirements are defined, documented and aligned with the objectives of the organisation.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M2", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M2", + "impl_anchor": "REQ 1.1.1-M2", + "condition": null, + "requirement": "A policy exists and is approved by the organisation's management.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M3", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M3", + "impl_anchor": "REQ 1.1.1-M3", + "condition": null, + "requirement": "The policy states the objectives and the importance of information security within the organisation.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M4", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M4", + "impl_anchor": "REQ 1.1.1-M4", + "condition": null, + "requirement": "The policies are made available to employees in a suitable form (e.g. intranet).", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M5", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M5", + "impl_anchor": "REQ 1.1.1-M5", + "condition": null, + "requirement": "Employees and external business partners are informed about changes relevant to them.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S1", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S1", + "impl_anchor": "REQ 1.1.1-S1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The information security requirements are based on the organisation's strategy; laws and contracts are taken into account in the policy.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S2", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S2", + "impl_anchor": "REQ 1.1.1-S2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The policy states the consequences of non-compliance.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S3", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S3", + "impl_anchor": "REQ 1.1.1-S3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Further relevant security policies are established.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S4", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S4", + "impl_anchor": "REQ 1.1.1-S4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Regular review and, where necessary, revision of the policies are established.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M1", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M1", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "The scope of the ISMS (the organisation governed by the ISMS) is defined.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M2", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M2", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "The organisation's requirements for the ISMS are determined.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M3", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M3", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "The organisation's management has commissioned and approved the ISMS.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M4", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M4", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "The ISMS provides management with suitable means for monitoring and steering (e.g. management review).", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M5", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M5", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "The applicable controls are determined (e.g. ISO 27001 statement of applicability or a completed ISA catalogue).", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M6", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M6", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "The effectiveness of the ISMS is reviewed regularly by management.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M1", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M1", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "Responsibilities for information security are defined, documented and assigned.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M2", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M2", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "The responsible employees are defined, qualified and enabled for their task.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M3", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M3", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "The necessary resources are available.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M4", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M4", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "The points of contact are known within the organisation and to relevant business partners.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-S1", + "policy": "R01", + "control": "1.2.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.2-S1", + "impl_anchor": "IMPL 1.2.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "An appropriate information security structure within the organisation is defined and documented.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-S2", + "policy": "R01", + "control": "1.2.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.2-S2", + "impl_anchor": "IMPL 1.2.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Security-relevant roles that are not part of the ISMS but are relevant to information security are taken into account.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-H1", + "policy": "R01", + "control": "1.2.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.2.2-H1", + "impl_anchor": "IMPL 1.2.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "An appropriate organisational separation of responsibilities is established to avoid conflicts of interest (segregation of duties). (C, I, A)", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.3-M1", + "policy": "R01", + "control": "1.2.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.3-M1", + "impl_anchor": "IMPL 1.2.3", + "condition": null, + "requirement": "Projects are classified taking information security requirements into account.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-S1", + "policy": "R01", + "control": "1.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.3-S1", + "impl_anchor": "IMPL 1.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Procedures and criteria for classifying projects are documented.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-S2", + "policy": "R01", + "control": "1.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.3-S2", + "impl_anchor": "IMPL 1.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A risk assessment following the defined procedure is carried out in an early project phase and repeated upon project changes.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-S3", + "policy": "R01", + "control": "1.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.3-S3", + "impl_anchor": "IMPL 1.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Measures are derived for identified information security risks and taken into account in the project.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-H1", + "policy": "R01", + "control": "1.2.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.2.3-H1", + "impl_anchor": "IMPL 1.2.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The derived measures are reviewed regularly during the project and reassessed when the assessment criteria change. (C, I, A)", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.3.1-M1", + "policy": "R02", + "control": "1.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.1-M1", + "impl_anchor": "IMPL 1.3.1", + "condition": null, + "requirement": "The organisation's information assets and other security-relevant assets are identified and recorded.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.1-M2", + "policy": "R02", + "control": "1.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.1-M2", + "impl_anchor": "IMPL 1.3.1", + "condition": null, + "requirement": "The supporting assets that process the information assets are identified and recorded.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.1-S1", + "policy": "R02", + "control": "1.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.1-S1", + "impl_anchor": "IMPL 1.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A catalogue of the relevant information assets exists; the relevant aspects are taken into account.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.2-M1", + "policy": "R02", + "control": "1.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.2-M1", + "impl_anchor": "IMPL 1.3.2", + "condition": null, + "requirement": "A consistent scheme for classifying information assets with regard to the protection goal of confidentiality is in place.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.2-M2", + "policy": "R02", + "control": "1.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.2-M2", + "impl_anchor": "IMPL 1.3.2", + "condition": null, + "requirement": "The identified information assets are assessed according to the defined criteria and assigned to the classification scheme.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.2-M3", + "policy": "R02", + "control": "1.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.2-M3", + "impl_anchor": "IMPL 1.3.2", + "condition": null, + "requirement": "Requirements for handling supporting assets (e.g. labelling, use, transport, storage, return, deletion/destruction) depending on the classification are in place and implemented.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.2-S1", + "policy": "R02", + "control": "1.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.2-S1", + "impl_anchor": "IMPL 1.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The protection goals of integrity and availability are taken into account.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.3-M1", + "policy": "R02", + "control": "1.3.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.3-M1", + "impl_anchor": "IMPL 1.3.3", + "condition": null, + "requirement": "External IT services are not used without an explicit assessment and implementation of the information security requirements; the relevant aspects are taken into account.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-M2", + "policy": "R02", + "control": "1.3.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.3-M2", + "impl_anchor": "IMPL 1.3.3", + "condition": null, + "requirement": "The external IT services are aligned with the protection need of the information assets processed.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S1", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S1", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Requirements for procurement, commissioning and approval in connection with the use of external IT services are determined and met.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S2", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S2", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A procedure for approval taking the protection need into account is established.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S3", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S3", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "External IT services and their approval are documented.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S4", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S4", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "It is regularly verified that only approved external IT services are used.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-M1", + "policy": "R02", + "control": "1.3.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.4-M1", + "impl_anchor": "IMPL 1.3.4", + "condition": null, + "requirement": "Software is approved before installation or use; the relevant aspects are taken into account.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-M2", + "policy": "R02", + "control": "1.3.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.4-M2", + "impl_anchor": "IMPL 1.3.4", + "condition": null, + "requirement": "The software approval also applies to special software such as maintenance tools.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S1", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S1", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The types of software to be managed (firmware, operating systems, applications, libraries, device drivers) are determined.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S2", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S2", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Repositories of the managed software exist.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S3", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S3", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The software repositories are protected against unauthorised manipulation.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S4", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S4", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The approval of software is reviewed regularly.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S5", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S5", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Software versions and patch levels are known.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-V1", + "policy": "R02", + "control": "1.3.4", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.3.4-V1", + "impl_anchor": "IMPL 1.3.4-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Additional requirements for software use (e.g. the need to control/monitor use) are determined where present. (C, I, A)", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-M1", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M1", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Risk assessments are carried out regularly and on an ad-hoc basis.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-M2", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M2", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Information security risks are assessed appropriately (e.g. likelihood of occurrence and potential extent of damage).", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-M3", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M3", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Information security risks are documented.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-M4", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M4", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "A responsible person (risk owner) is assigned to each information security risk and is responsible for its assessment and treatment.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-S1", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S1", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A procedure for the identification, assessment and treatment of security risks is in place.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-S2", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S2", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Criteria for the assessment and treatment of security risks exist.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-S3", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S3", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Risk treatment measures and their responsible persons are defined and documented; a measures plan or implementation overview is tracked.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-S4", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S4", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Upon changes in the environment (e.g. organisational structure, location, regulations), a reassessment is carried out promptly.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.5.1-M1", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M1", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Compliance with the policies is reviewed organisation-wide.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M2", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M2", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Information security policies and procedures are reviewed regularly.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M3", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M3", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Measures to correct possible deviations are initiated and tracked.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M4", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M4", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Compliance with information security requirements (e.g. technical specifications) is reviewed regularly.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M5", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M5", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "The results of the reviews carried out are recorded and retained.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-S1", + "policy": "R03", + "control": "1.5.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.5.1-S1", + "impl_anchor": "IMPL 1.5.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A plan for the content and framework conditions (schedule, scope, controls) of the reviews to be carried out is in place.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.2-M1", + "policy": "R03", + "control": "1.5.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.2-M1", + "impl_anchor": "IMPL 1.5.2", + "condition": null, + "requirement": "Information security reviews are carried out by an independent and competent body regularly and after fundamental changes.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.2-M2", + "policy": "R03", + "control": "1.5.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.2-M2", + "impl_anchor": "IMPL 1.5.2", + "condition": null, + "requirement": "Measures to correct possible deviations are initiated and tracked.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.2-S1", + "policy": "R03", + "control": "1.5.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.5.2-S1", + "impl_anchor": "IMPL 1.5.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The results of the reviews carried out are documented and reported to the organisation's management.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.6.1-M1", + "policy": "R04", + "control": "1.6.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.1-M1", + "impl_anchor": "IMPL 1.6.1", + "condition": null, + "requirement": "A definition of a reportable security event or observation exists and is known to employees and relevant stakeholders.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.1-M2", + "policy": "R04", + "control": "1.6.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.1-M2", + "impl_anchor": "IMPL 1.6.1", + "condition": null, + "requirement": "Appropriate, risk-oriented mechanisms for reporting security events are defined, implemented and known to all relevant reporters.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.1-M3", + "policy": "R04", + "control": "1.6.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.1-M3", + "impl_anchor": "IMPL 1.6.1", + "condition": null, + "requirement": "Appropriate channels for communicating with reporters exist.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S1", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S1", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A common point of contact for event reporting exists.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S2", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S2", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Different reporting channels depending on the perceived severity (real-time for serious events/emergencies as well as asynchronous mechanisms such as tickets or email) are available.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S3", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S3", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Employees are obliged and trained to report relevant events.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S4", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S4", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Security events can also be reported by external parties; the relevant aspects are taken into account.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S5", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S5", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The mechanism and the information on how incidents are reported are accessible to all relevant reporters.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S6", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S6", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A feedback procedure to the reporters is established.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-V1", + "policy": "R04", + "control": "1.6.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.1-V1", + "impl_anchor": "IMPL 1.6.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Tests and exercises of event and observation reporting are carried out regularly. (C, I, A)", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-M1", + "policy": "R04", + "control": "1.6.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.2-M1", + "impl_anchor": "IMPL 1.6.2", + "condition": null, + "requirement": "Reported events are processed without undue delay.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-M2", + "policy": "R04", + "control": "1.6.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.2-M2", + "impl_anchor": "IMPL 1.6.2", + "condition": null, + "requirement": "An appropriate response to reported security events is ensured.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-M3", + "policy": "R04", + "control": "1.6.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.2-M3", + "impl_anchor": "IMPL 1.6.2", + "condition": null, + "requirement": "Lessons learned feed into continual improvement.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-S1", + "policy": "R04", + "control": "1.6.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.2-S1", + "impl_anchor": "IMPL 1.6.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "During processing, reported events are categorised (e.g. personnel, physical, cyber), qualified (e.g. not security-relevant, observation, improvement suggestion, vulnerability, incident) and prioritised (e.g. low, medium, high, critical).", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-S2", + "policy": "R04", + "control": "1.6.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.2-S2", + "impl_anchor": "IMPL 1.6.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Responsibilities for handling events per category are defined and assigned.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-S3", + "policy": "R04", + "control": "1.6.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.2-S3", + "impl_anchor": "IMPL 1.6.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A strategy for reporting potentially criminally relevant aspects to the competent authorities, where necessary, exists. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H1", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H1", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Maximum response times per class, category and severity are defined. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H2", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H2", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Events not processed in line with their priority are escalated; the relevant aspects are taken into account. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H3", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H3", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Legal, regulatory and contractual reporting obligations and the associated contact information are known. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H4", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H4", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "A communication strategy for security-relevant events exists; the relevant aspects are taken into account. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H5", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H5", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Procedures for responding to security incidents at suppliers are established; the relevant aspects are taken into account. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-V1", + "policy": "R04", + "control": "1.6.2", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-V1", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "The handling of events of different categories and priorities is tested regularly; the relevant aspects are taken into account. (A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-M1", + "policy": "R04", + "control": "1.6.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.3-M1", + "impl_anchor": "IMPL 1.6.3", + "condition": null, + "requirement": "An appropriate plan for responding to and managing crisis situations exists and the necessary resources are available.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "1.6.3-M2", + "policy": "R04", + "control": "1.6.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.3-M2", + "impl_anchor": "IMPL 1.6.3", + "condition": null, + "requirement": "Responsibilities and authorities for crisis management are defined, documented and assigned.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-M3", + "policy": "R04", + "control": "1.6.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.3-M3", + "impl_anchor": "IMPL 1.6.3", + "condition": null, + "requirement": "The responsible employees are defined and qualified for their task.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S1", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S1", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Methods for detecting crisis situations are established; general indicators and specific foreseeable crises are identified.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "1.6.3-S2", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S2", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A procedure for triggering and/or escalating crisis management is in place.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S3", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S3", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Strategic objectives and their priority in crisis situations are defined and known to relevant personnel.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S4", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S4", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A crisis team is defined and approved.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S5", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S5", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Crisis policies and procedures are defined and approved.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S6", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S6", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The crisis planning is reviewed and updated regularly.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H1", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H1", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Relevant different potential crisis scenarios are identified.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H2", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H2", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The resources and information necessary for crisis management (e.g. communication infrastructure, availability of contact and risk information) are identified; appropriate measures to ensure availability or fallback planning are in place. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H3", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H3", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "A communication strategy for crisis situations exists. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H4", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H4", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The efficiency, feasibility and appropriateness of the crisis planning are assessed regularly. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H5", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H5", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Sample-based tests of the crisis planning are carried out (e.g. simulation, tabletop exercises with key personnel). (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-V1", + "policy": "R04", + "control": "1.6.3", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-V1", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Crisis exercises and simulations involving all relevant persons, including decision-makers, are carried out regularly. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.1-M1", + "policy": "R05", + "control": "2.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.1-M1", + "impl_anchor": "IMPL 2.1.1", + "condition": null, + "requirement": "Sensitive work areas and activities are determined.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-M2", + "policy": "R05", + "control": "2.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.1-M2", + "impl_anchor": "IMPL 2.1.1", + "condition": null, + "requirement": "The requirements for employees with regard to their job profiles are determined and met.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-M3", + "policy": "R05", + "control": "2.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.1-M3", + "impl_anchor": "IMPL 2.1.1", + "condition": null, + "requirement": "The identity of potential employees is verified (e.g. checking of identity documents).", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-S1", + "policy": "R05", + "control": "2.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.1-S1", + "impl_anchor": "IMPL 2.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The personal suitability of potential employees is checked using simple methods (e.g. job interview).", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-S2", + "policy": "R05", + "control": "2.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.1-S2", + "impl_anchor": "IMPL 2.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "An extended suitability check depending on the work area and the activity is carried out (e.g. assessment centre, checking of references, certificates and criminal record certificates).", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-M1", + "policy": "R05", + "control": "2.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.2-M1", + "impl_anchor": "IMPL 2.1.2", + "condition": null, + "requirement": "A confidentiality obligation is in force.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-M2", + "policy": "R05", + "control": "2.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.2-M2", + "impl_anchor": "IMPL 2.1.2", + "condition": null, + "requirement": "An obligation to comply with the information security policies is in force.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-S1", + "policy": "R05", + "control": "2.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.2-S1", + "impl_anchor": "IMPL 2.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A confidentiality obligation going beyond the employment contract is in force.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-S2", + "policy": "R05", + "control": "2.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.2-S2", + "impl_anchor": "IMPL 2.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Information security aspects are taken into account in the employees' employment contracts.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-S3", + "policy": "R05", + "control": "2.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.2-S3", + "impl_anchor": "IMPL 2.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A procedure for dealing with violations of these obligations is described.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.3-M1", + "policy": "R05", + "control": "2.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.3-M1", + "impl_anchor": "IMPL 2.1.3", + "condition": null, + "requirement": "Employees are trained and made aware.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "2.1.3-S1", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S1", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A concept for the awareness and training of employees is created.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "2.1.3-S2", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S2", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Target groups for training and awareness measures (e.g. managers, administrators, employees with access to customer networks, production personnel) are identified and taken into account in the concept.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S3", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S3", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The concept is approved by the responsible management.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S4", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S4", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Training and awareness measures are carried out regularly and on an ad-hoc basis.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S5", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S5", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Participation in training and awareness measures is documented.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S6", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S6", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Points of contact for information security are known to the employees.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-M1", + "policy": "R06", + "control": "2.1.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.4-M1", + "impl_anchor": "IMPL 2.1.4", + "condition": null, + "requirement": "The requirements for mobile working are determined and met; the relevant aspects are taken into account.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-S1", + "policy": "R06", + "control": "2.1.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.4-S1", + "impl_anchor": "IMPL 2.1.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The relevant aspects of mobile working are taken into account.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-S2", + "policy": "R06", + "control": "2.1.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.4-S2", + "impl_anchor": "IMPL 2.1.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Awareness of employees.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-H1", + "policy": "R06", + "control": "2.1.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 2.1.4-H1", + "impl_anchor": "IMPL 2.1.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Protective measures against eavesdropping and being overlooked are implemented. (C)", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-M1", + "policy": "R07", + "control": "3.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.1-M1", + "impl_anchor": "IMPL 3.1.1", + "condition": null, + "requirement": "A security zone concept including associated protective measures based on the requirements for handling information assets is in place.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-M2", + "policy": "R07", + "control": "3.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.1-M2", + "impl_anchor": "IMPL 3.1.1", + "condition": null, + "requirement": "The defined protective measures are implemented.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-M3", + "policy": "R07", + "control": "3.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.1-M3", + "impl_anchor": "IMPL 3.1.1", + "condition": null, + "requirement": "The code of conduct for security zones is known to all persons involved.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-S1", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S1", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Procedures for granting and revoking access rights are established.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S2", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S2", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Policies for visitor management (including registration and escorting of visitors) are defined.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S3", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S3", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Policies for carrying and using mobile IT devices and data media (e.g. registration, labelling obligations) are defined and implemented.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S4", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S4", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Network/infrastructure components (own or customer networks) are protected against unauthorised access.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S5", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S5", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "External premises used for storing/processing information assets are taken into account in the zone concept (e.g. storage rooms, workshops, test tracks, data centres).", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-H1", + "policy": "R07", + "control": "3.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 3.1.1-H1", + "impl_anchor": "IMPL 3.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Protective measures against simple eavesdropping and being overlooked are implemented. (C)", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.4-M1", + "policy": "R06", + "control": "3.1.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.4-M1", + "impl_anchor": "IMPL 3.1.4", + "condition": null, + "requirement": "The requirements for mobile IT devices and mobile data media are determined and met; the relevant aspects are taken into account.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.4-S1", + "policy": "R06", + "control": "3.1.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.4-S1", + "impl_anchor": "IMPL 3.1.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Registration of the IT devices.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.4-H1", + "policy": "R06", + "control": "3.1.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 3.1.4-H1", + "impl_anchor": "IMPL 3.1.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "General encryption of mobile data media or of the information assets stored on them. Where technically not feasible, information is protected by equivalent measures. (C, I)", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.1-M1", + "policy": "R08", + "control": "4.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.1-M1", + "impl_anchor": "IMPL 4.1.1", + "condition": null, + "requirement": "The requirements for handling means of identification throughout the entire lifecycle are determined and met; the relevant aspects are taken into account.", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.1-S1", + "policy": "R08", + "control": "4.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.1-S1", + "impl_anchor": "IMPL 4.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Means of identification can only be created under controlled conditions.", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.1.1-H1", + "policy": "R08", + "control": "4.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 4.1.1-H1", + "impl_anchor": "IMPL 4.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "A strategy for blocking or invalidating means of identification in the event of loss is prepared and, as far as possible, implemented. (C, I, A)", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-M1", + "policy": "R08", + "control": "4.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.2-M1", + "impl_anchor": "IMPL 4.1.2", + "condition": null, + "requirement": "The user authentication procedures are selected on the basis of a risk assessment; possible attack scenarios (e.g. direct reachability via the internet) have been taken into account.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-M2", + "policy": "R08", + "control": "4.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.2-M2", + "impl_anchor": "IMPL 4.1.2", + "condition": null, + "requirement": "State-of-the-art user authentication procedures are applied.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-S1", + "policy": "R08", + "control": "4.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.2-S1", + "impl_anchor": "IMPL 4.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The authentication procedures are defined and implemented on the basis of business and security requirements.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-S2", + "policy": "R08", + "control": "4.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.2-S2", + "impl_anchor": "IMPL 4.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Users are authenticated at least by strong passwords in line with established and recognised practices.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-S3", + "policy": "R08", + "control": "4.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.2-S3", + "impl_anchor": "IMPL 4.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "For privileged user accounts, higher-grade procedures are used (e.g. privileged access management, two-factor authentication).", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-H1", + "policy": "R08", + "control": "4.1.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 4.1.2-H1", + "impl_anchor": "IMPL 4.1.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Depending on the risk assessment, authentication and access control are strengthened by supplementary measures (e.g. continuous access monitoring, strong authentication, automatic log-off, lock upon inactivity, brute-force prevention). (C, I, A)", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-V1", + "policy": "R08", + "control": "4.1.2", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 4.1.2-V1", + "impl_anchor": "IMPL 4.1.2-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Before accessing data with a very high protection need, users are authenticated by means of strong authentication (e.g. two-factor) in line with the state of the art. (C, I)", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M1", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M1", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "The creation, modification and deletion of user accounts is carried out.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.1.3-M2", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M2", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Unique and personalised user accounts are used.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M3", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M3", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "The use of shared accounts is regulated (e.g. limited to cases where traceability is dispensable).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M4", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M4", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "User accounts are deactivated immediately after the user leaves (e.g. upon end of contract).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M5", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M5", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "User accounts are reviewed regularly.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M6", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M6", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "The log-on information is provided to the user in a secure manner.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M7", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M7", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "A policy for handling log-on information is defined and implemented; the relevant aspects are taken into account.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S1", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S1", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A base account with minimal access rights and functionalities exists and is used.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S10", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S10", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Interactive log-on for service accounts (technical accounts) is prevented technically.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S2", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S2", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Default accounts and passwords preconfigured by the manufacturer are deactivated (e.g. blocking or password change).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S3", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S3", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "User accounts are created or authorised by the responsible body.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S4", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S4", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The creation of user accounts is subject to an approval process (four-eyes principle).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S5", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S5", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "User accounts of service providers are deactivated after completion of their task.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S6", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S6", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Deadlines for deactivating and deleting user accounts are defined.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S7", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S7", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The use of default passwords is prevented technically.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S8", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S8", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "In the case of strong authentication, the use of the medium (e.g. possession factor) is secure.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S9", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S9", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "User accounts are reviewed regularly; this also includes accounts in customers' IT systems.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-M1", + "policy": "R08", + "control": "4.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.2.1-M1", + "impl_anchor": "IMPL 4.2.1", + "condition": null, + "requirement": "The requirements for managing access rights (authorisation) are determined and met; the relevant aspects are taken into account.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.2.1-M2", + "policy": "R08", + "control": "4.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.2.1-M2", + "impl_anchor": "IMPL 4.2.1", + "condition": null, + "requirement": "The access rights granted for normal and privileged user accounts as well as technical accounts are reviewed regularly, also in customers' IT systems.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.2.1-S1", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S1", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Strategies for authorising access to information are prepared.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.2.1-S2", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S2", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Authorisation roles are used.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-S3", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S3", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Rights are granted according to the need-to-use principle and in line with role and/or area of responsibility.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-S4", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S4", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Normal user accounts do not receive privileged access rights.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-S5", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S5", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The user's access rights are updated after a change in their responsibilities.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-H1", + "policy": "R08", + "control": "4.2.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 4.2.1-H1", + "impl_anchor": "IMPL 4.2.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The access rights are approved by the responsible internal information officer. (C, I, A)", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-V1", + "policy": "R08", + "control": "4.2.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 4.2.1-V1", + "impl_anchor": "IMPL 4.2.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Information is stored encrypted at content level (e.g. file level) to prevent unauthorised access (including by privileged users). Where encryption is not feasible, equivalent measures apply. (C)", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-V2", + "policy": "R08", + "control": "4.2.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 4.2.1-V2", + "impl_anchor": "IMPL 4.2.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Existing access rights are reviewed at shorter intervals (e.g. quarterly). (C)", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.1-M1", + "policy": "R09", + "control": "5.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.1-M1", + "impl_anchor": "IMPL 5.1.1", + "condition": null, + "requirement": "All cryptographic procedures used (e.g. encryption, signature, hash algorithms, protocols) provide the security required in the respective field of application according to a recognised industry standard, as far as legally possible.", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.1-S1", + "policy": "R09", + "control": "5.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.1-S1", + "impl_anchor": "IMPL 5.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A concept for the use of cryptography is defined and implemented; the relevant aspects are taken into account.", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.1-H1", + "policy": "R09", + "control": "5.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.1.1-H1", + "impl_anchor": "IMPL 5.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Requirements for key sovereignty (in particular in the case of external processing) are determined and met. (C, I)", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-M1", + "policy": "R09", + "control": "5.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.2-M1", + "impl_anchor": "IMPL 5.1.2", + "condition": null, + "requirement": "The network services used for transmitting information are identified and documented.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.2-M2", + "policy": "R09", + "control": "5.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.2-M2", + "impl_anchor": "IMPL 5.1.2", + "condition": null, + "requirement": "Policies and procedures in line with the classification requirements for the use of network services are defined and implemented.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-M3", + "policy": "R09", + "control": "5.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.2-M3", + "impl_anchor": "IMPL 5.1.2", + "condition": null, + "requirement": "Measures to protect transmitted content against unauthorised access are implemented.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-S1", + "policy": "R09", + "control": "5.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.2-S1", + "impl_anchor": "IMPL 5.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Measures to ensure correct addressing and correct transmission of information are implemented.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.2-S2", + "policy": "R09", + "control": "5.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.2-S2", + "impl_anchor": "IMPL 5.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Electronic data exchange takes place using content or transport encryption in line with the respective classification.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-S3", + "policy": "R09", + "control": "5.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.2-S3", + "impl_anchor": "IMPL 5.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Remote access connections to the organisation's network have appropriate security features; the relevant aspects are taken into account.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-H1", + "policy": "R09", + "control": "5.1.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.1.2-H1", + "impl_anchor": "IMPL 5.1.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Information is transmitted encrypted (at least transport encryption) or protected by equivalently effective measures. (C)", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-V1", + "policy": "R09", + "control": "5.1.2", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.1.2-V1", + "impl_anchor": "IMPL 5.1.2-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Information is transmitted with content encryption. (C)", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-M1", + "policy": "R10", + "control": "5.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.1-M1", + "impl_anchor": "IMPL 5.2.1", + "condition": null, + "requirement": "Information security requirements for changes to the organisation, business processes and IT systems are determined and met.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "5.2.1-S1", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S1", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A formal approval procedure is established.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-S2", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S2", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The possible effects of changes on information security are assessed.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-S3", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S3", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Changes with an effect on information security are planned and tested.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-S4", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S4", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Fallback procedures in the event of errors are taken into account.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-H1", + "policy": "R10", + "control": "5.2.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.1-H1", + "impl_anchor": "IMPL 5.2.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Compliance with the information security requirements is verified during and after the changes. (C, I, A)", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.2-M1", + "policy": "R10", + "control": "5.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.2-M1", + "impl_anchor": "IMPL 5.2.2", + "condition": null, + "requirement": "The IT systems have been subjected to a risk assessment to determine the need to separate them into development, test and production systems.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.2-M2", + "policy": "R10", + "control": "5.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.2-M2", + "impl_anchor": "IMPL 5.2.2", + "condition": null, + "requirement": "A segmentation is implemented on the basis of the results of the risk analysis.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.2-S1", + "policy": "R10", + "control": "5.2.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.2-S1", + "impl_anchor": "IMPL 5.2.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The requirements for development and test environments are determined and met; the relevant aspects are taken into account.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-M1", + "policy": "R10", + "control": "5.2.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.3-M1", + "impl_anchor": "IMPL 5.2.3", + "condition": null, + "requirement": "Requirements for protection against malware are determined.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-M2", + "policy": "R10", + "control": "5.2.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.3-M2", + "impl_anchor": "IMPL 5.2.3", + "condition": null, + "requirement": "Technical and organisational measures for protection against malware are defined and implemented.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S1", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S1", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Unnecessary network services are deactivated.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S2", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S2", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Access to network services is limited to what is necessary through appropriate protective measures.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S3", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S3", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Protective software against malware is installed and updated automatically at regular intervals (e.g. virus scanner).", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S4", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S4", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Received files and software are automatically checked for malware before execution (on-access scan).", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S5", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S5", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The entire data stock of all systems is checked for malware regularly.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S6", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S6", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Data transmitted via central gateways (e.g. email, internet, external networks) is automatically checked by protective software.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S7", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S7", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Measures preventing protective software from being deactivated or modified by users are defined and implemented.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S8", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S8", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "For IT systems without protective software, alternative measures are implemented (e.g. special resilience, few services, no active users, network isolation).", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M1", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M1", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Information security requirements for handling event logs are determined and met.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "5.2.4-M2", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M2", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Security-relevant requirements for logging the activities of administrators and users are determined and met.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M3", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M3", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "The IT systems used are assessed with regard to the need for logging.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M4", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M4", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "When external IT services are used, information on the monitoring options is obtained and taken into account in the assessment.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M5", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M5", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Event logs are checked regularly for policy violations and conspicuous problems, in compliance with the permissible legal and organisational requirements.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-S1", + "policy": "R10", + "control": "5.2.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.4-S1", + "impl_anchor": "IMPL 5.2.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A procedure for escalating relevant events to the responsible body is defined and established.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "5.2.4-S2", + "policy": "R10", + "control": "5.2.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.4-S2", + "impl_anchor": "IMPL 5.2.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Event logs (content and metadata) are protected against modification (e.g. by a dedicated environment).", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-S3", + "policy": "R10", + "control": "5.2.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.4-S3", + "impl_anchor": "IMPL 5.2.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Appropriate monitoring and recording of all information-security-relevant actions in the network is established.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-H1", + "policy": "R10", + "control": "5.2.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.4-H1", + "impl_anchor": "IMPL 5.2.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Security-relevant requirements for handling event logs, e.g. contractual requirements, are determined and implemented. (C, I, A)", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-H2", + "policy": "R10", + "control": "5.2.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.4-H2", + "impl_anchor": "IMPL 5.2.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Events relating to the establishment and termination of remote access sessions (e.g. remote maintenance) are logged. (C, I, A)", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-V1", + "policy": "R10", + "control": "5.2.4", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.4-V1", + "impl_anchor": "IMPL 5.2.4-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Logging of every access to data with a very high protection need, as far as technically feasible and legally/organisationally permissible. (C, I)", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-M1", + "policy": "R10", + "control": "5.2.5", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.5-M1", + "impl_anchor": "IMPL 5.2.5", + "condition": null, + "requirement": "Information about technical vulnerabilities of the IT systems used is collected (e.g. manufacturer information, system audits, CVE database).", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04", + "VA-06" + ] + }, + { + "id": "5.2.5-M2", + "policy": "R10", + "control": "5.2.5", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.5-M2", + "impl_anchor": "IMPL 5.2.5", + "condition": null, + "requirement": "Potentially affected IT systems and software are identified and the risk caused by the vulnerability is assessed.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-M3", + "policy": "R10", + "control": "5.2.5", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.5-M3", + "impl_anchor": "IMPL 5.2.5", + "condition": null, + "requirement": "Risks arising from vulnerabilities are treated.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-S1", + "policy": "R10", + "control": "5.2.5", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.5-S1", + "impl_anchor": "IMPL 5.2.5", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Appropriate patch management is defined and implemented (e.g. patch testing and installation).", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-06" + ] + }, + { + "id": "5.2.5-S2", + "policy": "R10", + "control": "5.2.5", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.5-S2", + "impl_anchor": "IMPL 5.2.5", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Risk-mitigating measures are implemented where necessary.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-S3", + "policy": "R10", + "control": "5.2.5", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.5-S3", + "impl_anchor": "IMPL 5.2.5", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The successful installation of patches is verified in a suitable manner.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M1", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M1", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "Requirements for the review (audit) of IT systems or services are determined.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-06" + ] + }, + { + "id": "5.2.6-M2", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M2", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "The scope of the system review is defined in good time.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M3", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M3", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "System or service reviews are coordinated with the operators and users of the IT systems/services.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M4", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M4", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "The results of system/service reviews are stored in a traceable manner and reported to the responsible management.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M5", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M5", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "Measures are derived from the results and implemented within an appropriate period.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-S1", + "policy": "R10", + "control": "5.2.6", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.6-S1", + "impl_anchor": "IMPL 5.2.6", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "System and service reviews are planned taking possible security risks (e.g. disruptions) into account.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-S2", + "policy": "R10", + "control": "5.2.6", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.6-S2", + "impl_anchor": "IMPL 5.2.6", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Regular system or service reviews are carried out; the relevant aspects are taken into account.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-S3", + "policy": "R10", + "control": "5.2.6", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.6-S3", + "impl_anchor": "IMPL 5.2.6", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Within an appropriate period after completion of the review, a report is prepared.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-H1", + "policy": "R10", + "control": "5.2.6", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.6-H1", + "impl_anchor": "IMPL 5.2.6-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "For critical IT systems/services, additional review requirements have been identified and are met (e.g. service-specific tests/tools and/or manual penetration tests, risk-based intervals). (A)", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-V1", + "policy": "R10", + "control": "5.2.6", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.6-V1", + "impl_anchor": "IMPL 5.2.6-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "IT systems and services are scanned regularly for vulnerabilities. For systems/services that cannot be scanned, suitable protective measures are to be implemented. (C, I, A)", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-M1", + "policy": "R10", + "control": "5.2.7", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.7-M1", + "impl_anchor": "IMPL 5.2.7", + "condition": null, + "requirement": "Requirements for the management and control of networks are determined and met.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-M2", + "policy": "R10", + "control": "5.2.7", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.7-M2", + "impl_anchor": "IMPL 5.2.7", + "condition": null, + "requirement": "Requirements for network segmentation are determined and met.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-S1", + "policy": "R10", + "control": "5.2.7", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.7-S1", + "impl_anchor": "IMPL 5.2.7", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Procedures for the management and control of networks are defined.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-S2", + "policy": "R10", + "control": "5.2.7", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.7-S2", + "impl_anchor": "IMPL 5.2.7", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "For a risk-based network segmentation, the relevant aspects are taken into account.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-H1", + "policy": "R10", + "control": "5.2.7", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.7-H1", + "impl_anchor": "IMPL 5.2.7-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Extended requirements for the management and control of networks are determined and implemented. (C, I, A)", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-M1", + "policy": "R04", + "control": "5.2.8", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.8-M1", + "impl_anchor": "IMPL 5.2.8", + "condition": null, + "requirement": "Critical IT services are identified and the business impact is taken into account.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "5.2.8-M2", + "policy": "R04", + "control": "5.2.8", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.8-M2", + "impl_anchor": "IMPL 5.2.8", + "condition": null, + "requirement": "Requirements and responsibilities for the continuity and recovery of these IT services are known to relevant stakeholders and fulfilled.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-S1", + "policy": "R04", + "control": "5.2.8", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.8-S1", + "impl_anchor": "IMPL 5.2.8", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Critical IT systems are identified; the relevant aspects are taken into account.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "5.2.8-S2", + "policy": "R04", + "control": "5.2.8", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.8-S2", + "impl_anchor": "IMPL 5.2.8", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A continuity plan exists and is reviewed and updated regularly.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-S3", + "policy": "R04", + "control": "5.2.8", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.8-S3", + "impl_anchor": "IMPL 5.2.8", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The continuity planning covers at least (D)DoS attacks, successful ransomware attacks and other sabotage, system failure scenarios as well as natural disasters affecting critical IT systems.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H1", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H1", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The continuity planning contains predefined time frames (recovery time objective) for the resumption of operations. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H2", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H2", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Appropriate SLAs with external service providers in line with the continuity planning are in place. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H3", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H3", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The continuity plans include the coordination of contractually agreed communication with business partners. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H4", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H4", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The continuity planning is tested regularly, incl. full recovery to a known state and adherence to defined target times. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H5", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H5", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "A backup and recovery strategy for critical IT services and information is defined and implemented. (C, I, A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H6", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H6", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Backups of critical IT services and information are sufficiently protected against unauthorised modification/deletion by malware. (I, A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H7", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H7", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Backups of critical IT services and information are sufficiently protected against unauthorised access by malware or operators. (C, I)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-V1", + "policy": "R04", + "control": "5.2.8", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-V1", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "The continuity planning is coordinated with the continuity plans of relevant external service providers. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-V2", + "policy": "R04", + "control": "5.2.8", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-V2", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "The continuation of essential core and business functions with minimal or no loss of operational continuity is possible; the relevant aspects are taken into account.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-V3", + "policy": "R04", + "control": "5.2.8", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-V3", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "The continuity planning is tested regularly. Test scenarios, results and lessons learned are recorded. (I, A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-M1", + "policy": "R10", + "control": "5.2.9", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.9-M1", + "impl_anchor": "IMPL 5.2.9", + "condition": null, + "requirement": "Backup concepts exist for relevant IT systems. Appropriate protective measures for the confidentiality, integrity and availability of the backups are taken into account.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "5.2.9-M2", + "policy": "R10", + "control": "5.2.9", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.9-M2", + "impl_anchor": "IMPL 5.2.9", + "condition": null, + "requirement": "Recovery concepts exist for relevant IT services.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "5.2.9-S1", + "policy": "R10", + "control": "5.2.9", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.9-S1", + "impl_anchor": "IMPL 5.2.9", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "For each relevant IT service, a backup and recovery concept exists. Dependencies between IT services and the recovery sequence are taken into account.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "5.2.9-H1", + "policy": "R10", + "control": "5.2.9", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-H1", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Backup and recovery concepts are reviewed methodically at regular intervals. (A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-H2", + "policy": "R10", + "control": "5.2.9", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-H2", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The fundamental recoverability is taken into account and tested (e.g. sample tests, test systems). (I, A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-V1", + "policy": "R10", + "control": "5.2.9", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-V1", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "(Additional) backups are carried out via offline procedures, immutable backups or an isolated IAM solution. (I, A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-V2", + "policy": "R10", + "control": "5.2.9", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-V2", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Recovery procedures are tested technically and methodically at regular intervals. (I, A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-V3", + "policy": "R10", + "control": "5.2.9", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-V3", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Geographical redundancy is taken into account in backup and recovery concepts. (A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.3.1-M1", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M1", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "The information security requirements associated with the design and development of an IT service are determined and taken into account.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-M2", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M2", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "The information security requirements associated with the procurement or extension of IT services and components are determined and taken into account.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-M3", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M3", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "Information security requirements in connection with changes to developed IT services are taken into account.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-M4", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M4", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "System acceptance tests are carried out taking the information security requirements into account.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S1", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S1", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Requirement specifications are created; the relevant aspects are taken into account.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S2", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S2", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Requirement specifications are checked against the information security requirements.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S3", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S3", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The IT service is checked for compliance with the specifications before production use.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S4", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S4", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The use of production data for test purposes is avoided as far as possible (anonymisation/pseudonymisation where applicable); the relevant aspects are taken into account.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S5", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S5", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Test systems receive protective measures comparable to the production environment when production data is used for testing.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-V1", + "policy": "R11", + "control": "5.3.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.3.1-V1", + "impl_anchor": "IMPL 5.3.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "The security of purpose-built or substantially adapted software is tested upon commissioning, upon substantial changes or regularly (e.g. penetration test). (C, I, A)", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-M1", + "policy": "R11", + "control": "5.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.2-M1", + "impl_anchor": "IMPL 5.3.2", + "condition": null, + "requirement": "Requirements for the information security of network services are determined and met.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-S1", + "policy": "R11", + "control": "5.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.2-S1", + "impl_anchor": "IMPL 5.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A procedure for securing and using network services is defined and implemented.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-S2", + "policy": "R11", + "control": "5.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.2-S2", + "impl_anchor": "IMPL 5.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The requirements are agreed in the form of SLAs.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-S3", + "policy": "R11", + "control": "5.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.2-S3", + "impl_anchor": "IMPL 5.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Appropriate redundancy solutions are implemented.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-H1", + "policy": "R11", + "control": "5.3.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.3.2-H1", + "impl_anchor": "IMPL 5.3.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Procedures for monitoring the quality of network traffic (e.g. traffic flow analyses, availability measurements) are defined and carried out. (A)", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.3-S1", + "policy": "R11", + "control": "5.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.3-S1", + "impl_anchor": "IMPL 5.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A description of the termination process is in place, adapted to changes and regulated contractually.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.3.4-M1", + "policy": "R12", + "control": "5.3.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.4-M1", + "impl_anchor": "IMPL 5.3.4", + "condition": null, + "requirement": "An effective separation (e.g. tenant separation) prevents unauthorised users of other organisations from accessing one's own information.", + "link": "{{LINK:R12#5.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-S1", + "policy": "R12", + "control": "5.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.4-S1", + "impl_anchor": "IMPL 5.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The provider's separation concept is documented and adapted to changes; the relevant aspects are taken into account.", + "link": "{{LINK:R12#5.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-M1", + "policy": "R12", + "control": "5.3.4-KI", + "level": "must", + "type": "MUSS", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-M1", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": null, + "requirement": "The use of AI/GenAI services is regulated; only approved services are used.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-M2", + "policy": "R12", + "control": "5.3.4-KI", + "level": "must", + "type": "MUSS", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-M2", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": null, + "requirement": "The input of confidential or personal information into non-approved AI services is prohibited; the permissible data classes per service are defined.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-M3", + "policy": "R12", + "control": "5.3.4-KI", + "level": "must", + "type": "MUSS", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-M3", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": null, + "requirement": "For approved AI services, it is clarified and contractually ensured that inputs are not used for training or passed on.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-S1", + "policy": "R12", + "control": "5.3.4-KI", + "level": "should", + "type": "SOLL", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-S1", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Results of AI services are reviewed before business-critical use (human in the loop); the use of AI is documented and regulatory requirements (e.g. EU AI Act) are taken into account.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "6.1.1-M1", + "policy": "R13", + "control": "6.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.1-M1", + "impl_anchor": "IMPL 6.1.1", + "condition": null, + "requirement": "Contractors and partners are subjected to a security risk assessment.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.1-M2", + "policy": "R13", + "control": "6.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.1-M2", + "impl_anchor": "IMPL 6.1.1", + "condition": null, + "requirement": "An appropriate level of information security is ensured through contractual agreements with contractors and partners.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.1-M3", + "policy": "R13", + "control": "6.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.1-M3", + "impl_anchor": "IMPL 6.1.1", + "condition": null, + "requirement": "Where applicable, contractual agreements with clients/customers are passed on to contractors and partners.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-S1", + "policy": "R13", + "control": "6.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.1-S1", + "impl_anchor": "IMPL 6.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Contractors and partners are contractually obliged to pass on requirements for an appropriate level of information security to their subcontractors.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.1-S2", + "policy": "R13", + "control": "6.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.1-S2", + "impl_anchor": "IMPL 6.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Performance reports and documents from contractors and partners are reviewed.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-H1", + "policy": "R13", + "control": "6.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-H1", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "It is demonstrated that the supplier's level of information security is appropriate to the protection need (e.g. reviewed questionnaire/self-disclosure, attestation, certificate, supplier audit). (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-H2", + "policy": "R13", + "control": "6.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-H2", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The degree of fulfilment of the required evidence by the supplier is documented, reviewed and monitored regularly and upon changes. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-H3", + "policy": "R13", + "control": "6.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-H3", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The supplier's compliance with contractual agreements is checked, documented, reviewed and monitored regularly and upon changes. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-V1", + "policy": "R13", + "control": "6.1.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-V1", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "The appropriate level of information security should be demonstrated by a third-party audit (an appropriate TISAX label or similar) or an appropriate supplier audit. Without an audit, management must make a risk-based decision to continue; evidence of this decision exists. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-V2", + "policy": "R13", + "control": "6.1.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-V2", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Contractual obligations towards customers regarding transparency of supply chain risks are fulfilled. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-M1", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M1", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "The confidentiality requirements are determined and met.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.2-M2", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M2", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "Requirements and procedures for applying confidentiality agreements are known to all persons who pass on information requiring protection.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-M3", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M3", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "Valid confidentiality agreements are concluded before information requiring protection is passed on.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-M4", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M4", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "The requirements and procedures for using confidentiality agreements and for handling information requiring protection are reviewed regularly.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S1", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S1", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Templates for confidentiality agreements are available and checked for legal applicability.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.2-S2", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S2", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Confidentiality agreements cover the persons/organisations involved, the type of information, the subject matter, the period of validity and the responsibilities of the obligated party.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S3", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S3", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Confidentiality agreements contain provisions for handling information requiring protection beyond the contractual relationship.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S4", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S4", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ways to demonstrate compliance (e.g. review by independent third parties or audit rights) are defined.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S5", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S5", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "A process for monitoring the period of validity of temporary confidentiality agreements and for timely renewal is defined and implemented.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M1", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M1", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "The IT services concerned are identified.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.3-M2", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M2", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "The security requirements relevant to the IT service are determined.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M3", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M3", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "The organisation responsible for implementing the requirement is defined and aware of its responsibility.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M4", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M4", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "Mechanisms for shared responsibilities are specified and implemented.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M5", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M5", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "The responsible organisation fulfils its respective responsibilities.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-S1", + "policy": "R13", + "control": "6.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.3-S1", + "impl_anchor": "IMPL 6.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "For IT services, the configuration is designed, implemented and documented on the basis of the necessary security requirements.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-S2", + "policy": "R13", + "control": "6.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.3-S2", + "impl_anchor": "IMPL 6.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The responsible personnel is appropriately trained.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H1", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H1", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "A list of the IT services concerned and the respective responsible IT service providers exists. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H2", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H2", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The applicability of the ISA controls has been assessed and documented. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H3", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H3", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The service configuration is included in the regular security assessments. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H4", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H4", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "It is demonstrated that the IT service providers fulfil their responsibility. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H5", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H5", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "The integration into local protective measures (e.g. secure authentication mechanisms) is established and documented. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.1.1-M1", + "policy": "R14", + "control": "7.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.1-M1", + "impl_anchor": "IMPL 7.1.1", + "condition": null, + "requirement": "Legal, regulatory and contractual requirements relevant to information security are determined regularly.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.1-M2", + "policy": "R14", + "control": "7.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.1-M2", + "impl_anchor": "IMPL 7.1.1", + "condition": null, + "requirement": "Policies for complying with the requirements are defined, implemented and communicated to the responsible persons.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.1-S1", + "policy": "R14", + "control": "7.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 7.1.1-S1", + "impl_anchor": "IMPL 7.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "The integrity of records in accordance with legal, regulatory and contractual requirements as well as business requirements is taken into account.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.2-M1", + "policy": "R14", + "control": "7.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.2-M1", + "impl_anchor": "IMPL 7.1.2", + "condition": null, + "requirement": "Legal and contractual information security requirements for procedures and processes when processing personal data are determined.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.2-M2", + "policy": "R14", + "control": "7.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.2-M2", + "impl_anchor": "IMPL 7.1.2", + "condition": null, + "requirement": "Provisions for complying with legal and contractual requirements for the protection of personal data are defined and known to the persons involved.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.2-M3", + "policy": "R14", + "control": "7.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.2-M3", + "impl_anchor": "IMPL 7.1.2", + "condition": null, + "requirement": "Processes and procedures for protecting personal data are taken into account in the information security management system.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "8.1.1-M1", + "policy": "P01", + "control": "8.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 8.1.1-M1", + "impl_anchor": "REQ 8.1.1-M1", + "condition": "FLAG_PROTOTYPE_PROTECTION", + "requirement": "Areas in which prototypes are processed or stored are protected by defined security zones and an effective perimeter.", + "implementation": "Prototype areas are designated as a dedicated security zone with access control, perimeter protection and logging.", + "link": "{{LINK:P01#8.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-20" + ] + }, + { + "id": "8.2.1-M1", + "policy": "P01", + "control": "8.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 8.2.1-M1", + "impl_anchor": "REQ 8.2.1-M1", + "condition": "FLAG_PROTOTYPE_PROTECTION", + "requirement": "Confidentiality obligations exist for prototypes; the associated information is classified and labelled.", + "implementation": "All persons involved with prototypes sign confidentiality agreements; prototypes are classified as confidential or higher.", + "link": "{{LINK:P01#8.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "8.3.1-M1", + "policy": "P01", + "control": "8.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 8.3.1-M1", + "impl_anchor": "REQ 8.3.1-M1", + "condition": "FLAG_PROTOTYPE_PROTECTION", + "requirement": "Transport and storage of prototypes are carried out according to documented protection requirements that ensure confidentiality and integrity.", + "implementation": "Transport and storage follow the procedure instruction VA-20: secured containers, logged handovers, access and visual protection.", + "link": "{{LINK:P01#8.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-20" + ] + }, + { + "id": "9.1.1-M1", + "policy": "D01", + "control": "9.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 9.1.1-M1", + "impl_anchor": "REQ 9.1.1-M1", + "condition": "FLAG_PERSONAL_DATA", + "requirement": "Responsibilities for data protection are appointed and the data protection organisation is documented.", + "implementation": "The role of data protection officer is appointed and integrated into the ISMS organisation; tasks and reporting paths are documented.", + "link": "{{LINK:D01#9.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "9.2.1-M1", + "policy": "D01", + "control": "9.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 9.2.1-M1", + "impl_anchor": "REQ 9.2.1-M1", + "condition": "FLAG_PERSONAL_DATA", + "requirement": "Processing of personal data is lawful, purpose-bound and recorded in a record of processing activities.", + "implementation": "A record of processing activities is maintained; legal basis, purpose and deletion periods are documented for each processing activity.", + "link": "{{LINK:D01#9.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + } + ], + "verfahren": [ + { + "id": "VA-01", + "title": "Incident-Response- und Meldeverfahren", + "file": "verfahren/VA-01_Incident-Response-und-Meldeverfahren.md", + "policy": "R04", + "fulfills": [ + "1.6.1-M1", + "1.6.1-M2", + "1.6.2-M1", + "1.6.2-M2", + "1.6.2-S1", + "1.6.2-S2" + ], + "link": "{{LINK:VA-01}}" + }, + { + "id": "VA-02", + "title": "IT-Notfall- und Wiederanlaufverfahren (BCM)", + "file": "verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md", + "policy": "R04", + "fulfills": [ + "1.6.3-M1", + "1.6.3-S1", + "5.2.8-M1", + "5.2.8-S1" + ], + "link": "{{LINK:VA-02}}" + }, + { + "id": "VA-03", + "title": "Berechtigungsverfahren (Joiner/Mover/Leaver und Rezertifizierung)", + "file": "verfahren/VA-03_Berechtigungsverfahren.md", + "policy": "R08", + "fulfills": [ + "4.1.1-S1", + "4.1.3-M1", + "4.2.1-M1", + "4.2.1-M2", + "4.2.1-S1" + ], + "link": "{{LINK:VA-03}}" + }, + { + "id": "VA-04", + "title": "Change- und Patch-Management-Verfahren", + "file": "verfahren/VA-04_Change-und-Patch-Management-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.1-M1", + "5.2.5-M1" + ], + "link": "{{LINK:VA-04}}" + }, + { + "id": "VA-05", + "title": "Backup- und Restore-Verfahren", + "file": "verfahren/VA-05_Backup-und-Restore-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.9-M1", + "5.2.9-M2", + "5.2.9-S1" + ], + "link": "{{LINK:VA-05}}" + }, + { + "id": "VA-06", + "title": "Schwachstellenmanagement-Verfahren", + "file": "verfahren/VA-06_Schwachstellenmanagement-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.5-M1", + "5.2.5-S1", + "5.2.6-M1" + ], + "link": "{{LINK:VA-06}}" + }, + { + "id": "VA-07", + "title": "Kryptokonzept und Schlüsselverwaltung", + "file": "verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md", + "policy": "R09", + "fulfills": [ + "5.1.1-M1", + "5.1.1-M2", + "5.1.1-S1", + "5.1.2-M1", + "5.1.2-S1" + ], + "link": "{{LINK:VA-07}}" + }, + { + "id": "VA-08", + "title": "Asset- und Klassifizierungsverfahren", + "file": "verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md", + "policy": "R02", + "fulfills": [ + "1.3.1-M1", + "1.3.1-M2", + "1.3.1-S1", + "1.3.2-M1", + "1.3.2-M2", + "1.3.2-S1" + ], + "link": "{{LINK:VA-08}}" + }, + { + "id": "VA-09", + "title": "Risikomanagement-Verfahren", + "file": "verfahren/VA-09_Risikomanagement-Verfahren.md", + "policy": "R03", + "fulfills": [ + "1.4.1-M1", + "1.4.1-M2", + "1.4.1-M3", + "1.4.1-S1" + ], + "link": "{{LINK:VA-09}}" + }, + { + "id": "VA-10", + "title": "Lieferanten-Onboarding- und Bewertungsverfahren", + "file": "verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md", + "policy": "R13", + "fulfills": [ + "6.1.1-M1", + "6.1.1-M2", + "6.1.1-S1", + "6.1.2-M1", + "6.1.2-S1", + "6.1.3-M1" + ], + "link": "{{LINK:VA-10}}" + }, + { + "id": "VA-11", + "title": "Cloud- und KI-Freigabeverfahren", + "file": "verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md", + "policy": "R12", + "fulfills": [ + "5.3.4-M1", + "5.3.4-M2", + "5.3.4-S1", + "5.3.4-KI-M1", + "5.3.4-KI-M2", + "5.3.4-KI-M3", + "5.3.4-KI-S1" + ], + "link": "{{LINK:VA-11}}" + }, + { + "id": "VA-12", + "title": "Awareness- und Schulungsverfahren", + "file": "verfahren/VA-12_Awareness-und-Schulungsverfahren.md", + "policy": "R05", + "fulfills": [ + "2.1.3-M1", + "2.1.3-S1" + ], + "link": "{{LINK:VA-12}}" + }, + { + "id": "VA-13", + "title": "Logging- und Monitoring-Verfahren", + "file": "verfahren/VA-13_Logging-und-Monitoring-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.4-M1", + "5.2.4-S1" + ], + "link": "{{LINK:VA-13}}" + }, + { + "id": "VA-14", + "title": "Personalsicherheit – Eignungsprüfung & sensible Tätigkeiten", + "file": "verfahren/VA-14_Personalsicherheit-Eignungspruefung.md", + "policy": "R05", + "fulfills": [ + "2.1.1-M1", + "2.1.1-M2", + "2.1.1-M3", + "2.1.1-S1", + "2.1.1-S2", + "2.1.2-M1", + "2.1.2-M2", + "2.1.2-S1", + "2.1.2-S2", + "2.1.2-S3" + ], + "link": "{{LINK:VA-14}}" + }, + { + "id": "VA-15", + "title": "Interne Audits & Complianceprüfungen", + "file": "verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md", + "policy": "R03", + "fulfills": [ + "1.5.1-M1", + "1.5.1-M2", + "1.5.1-M3", + "1.5.1-M4", + "1.5.1-M5", + "1.5.1-S1", + "1.5.2-M1", + "1.5.2-M2", + "1.5.2-S1" + ], + "link": "{{LINK:VA-15}}" + }, + { + "id": "VA-16", + "title": "Sichere Beschaffung, Entwicklung & Abnahme", + "file": "verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md", + "policy": "R11", + "fulfills": [ + "5.3.1-M1", + "5.3.1-M2", + "5.3.1-M3", + "5.3.1-M4", + "5.3.1-S1", + "5.3.1-S2", + "5.3.1-S3", + "5.3.1-S4", + "5.3.1-S5", + "5.3.1-V1", + "5.3.2-M1", + "5.3.2-S1", + "5.3.2-S2", + "5.3.2-S3", + "5.3.2-H1" + ], + "link": "{{LINK:VA-16}}" + }, + { + "id": "VA-17", + "title": "Zutritts- & Besuchermanagement (physisch)", + "file": "verfahren/VA-17_Zutritts-und-Besuchermanagement.md", + "policy": "R07", + "fulfills": [ + "3.1.1-S1", + "3.1.1-S2", + "3.1.1-S3", + "3.1.1-S4", + "3.1.1-S5" + ], + "link": "{{LINK:VA-17}}" + }, + { + "id": "VA-18", + "title": "Datenschutz- & Compliance-Pflege", + "file": "verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md", + "policy": "R14", + "fulfills": [ + "7.1.1-M1", + "7.1.1-M2", + "7.1.1-S1", + "7.1.2-M1", + "7.1.2-M2", + "7.1.2-M3" + ], + "link": "{{LINK:VA-18}}" + }, + { + "id": "VA-19", + "title": "Informationssicherheit in Projekten", + "file": "verfahren/VA-19_Informationssicherheit-in-Projekten.md", + "policy": "R01", + "fulfills": [ + "1.2.3-M1", + "1.2.3-S1", + "1.2.3-S2", + "1.2.3-S3", + "1.2.3-H1" + ], + "link": "{{LINK:VA-19}}" + }, + { + "id": "VA-20", + "title": "Prototypen-Zutritt und -Transport", + "file": "verfahren/VA-20_Prototypen-Zutritt-und-Transport.md", + "policy": "P01", + "fulfills": [ + "8.1.1-M1", + "8.3.1-M1" + ], + "link": "{{LINK:VA-20}}" + } + ] +} diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/D01_Datenschutz.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/D01_Datenschutz.md new file mode 100644 index 0000000..bc5f6c4 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/D01_Datenschutz.md @@ -0,0 +1,49 @@ +# Policy Data Protection + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_DPO}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the protection of personal data (assessment objective data protection, VDA ISA chapter 9). It elaborates the information security policy ({{LINK:L00}}) and complements the policy Compliance and Data Protection ({{LINK:R14}}). + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}), insofar as personal data is processed. + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA, chapter 9) and **Implementation at {{ORG_NAME}}**. + +{{#if FLAG_PERSONAL_DATA}} +### 3.1 Data protection organisation (ISA 9.1.1) + +**Requirement** + + +- **[MUST]** Responsibilities for data protection are appointed and the data protection organisation is documented. + +**Implementation at {{ORG_NAME}}** + +The role {{ROLE_DPO}} is appointed and integrated into the ISMS organisation. Tasks, reporting paths and escalation are documented. + +### 3.2 Lawfulness and record of processing activities (ISA 9.2.1) + +**Requirement** + + +- **[MUST]** Processing of personal data is lawful, purpose-bound and recorded in a record of processing activities. + +**Implementation at {{ORG_NAME}}** + +A record of processing activities is maintained and updated regularly. For each processing activity, the legal basis, purpose and deletion periods are documented. +{{/if}} diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/L00_Informationssicherheitsleitlinie.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/L00_Informationssicherheitsleitlinie.md new file mode 100644 index 0000000..79b87d6 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/L00_Informationssicherheitsleitlinie.md @@ -0,0 +1,175 @@ +# Information Security Policy + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + +## 1. Purpose + + +This information security policy describes the fundamental requirements, objectives and responsibilities of {{ORG_NAME}} for protecting information, IT systems, business processes and supporting assets. The information security requirements are defined, documented and aligned with the objectives of {{ORG_NAME}}. + +The objective is to ensure an appropriate level of information security and to meet the requirements of VDA ISA 2027 in the area of information security. + +## 2. Scope + +This policy applies to the defined ISMS scope: + +{{ISMS_SCOPE_DESCRIPTION}} + +It applies to: + +- all employees within the scope, +- managers, +- external service providers, insofar as they have access to the organisation's information, systems or processes, +- relevant IT systems, information, applications, sites and business processes within the ISMS scope. + +## 3. Information security objectives + + +The policy states the objectives and the importance of information security. Through the ISMS, the organisation pursues in particular the following objectives: + +- protection of confidential information against unauthorised access, +- ensuring the integrity of information and systems, +- ensuring the availability of business-critical information, systems and services, +- compliance with legal, regulatory and contractual requirements, +- appropriate protection of customer information, personal data, trade secrets and other information requiring protection, +- structured identification, assessment and treatment of information security risks, +- continual improvement of information security. + +## 4. Information security principles + +Information security is based on the following principles: + +### 4.1 Risk orientation +Information security measures are planned, implemented, reviewed and improved in a risk-oriented manner. Risks are assessed and tracked in the ISMS tool in use ({{TOOL_NAME}}) (see {{LINK:R03}}). + +### 4.2 Appropriateness +Protective measures must be appropriate to the protection needs of the information, systems and processes. Confidentiality, integrity and availability are taken into account. + +### 4.3 Responsibility +Information security is a shared responsibility of all employees. {{ROLE_MANAGEMENT}} holds overall responsibility for the ISMS. + +### 4.4 Traceability +Decisions, assessments, approvals and material measures relating to information security must be documented in a traceable manner. + +### 4.5 Continual improvement +The ISMS is reviewed regularly and adjusted where necessary. Findings from audits, incidents, risks, changes and management reviews feed into the improvement. + +## 5. Information security requirements + + +{{#if FLAG_INCLUDE_SHOULD}}The information security requirements are based on the strategy of {{ORG_NAME}}; legal and contractual requirements are taken into account. {{/if}}The organisation determines and documents information security requirements on the basis of: + +- legal and regulatory requirements, +- contractual requirements, in particular from customers and partners, +- requirements from the VDA ISA, +- internal business requirements, +- results of risk analyses, +- protection needs of information, processes and IT systems, +- requirements from projects, changes and external IT services. + +The relevant requirements in each case are taken into account in the ISMS and implemented through suitable policies, processes, technical measures and evidence. + +## 6. Roles and responsibilities + +The organisation defines roles and responsibilities for information security. These include at least: + +| Role | Fundamental responsibility | +|-------|------------------------------| +| {{ROLE_MANAGEMENT}} | Overall responsibility, approval of the information security policy, provision of appropriate resources | +| {{ROLE_ISB}} | Steering, maintenance and further development of the ISMS | +| Managers | Implementation of the requirements within their respective area of responsibility | +| {{ROLE_IT_LEAD}} | Implementation of technical and organisational security measures in the IT area | +| Asset owners / process owners | Assessment and maintenance of relevant information, processes and assets in the ISMS tool | +| Employees | Compliance with the policies and reporting of security events | +| External service providers | Compliance with contractually agreed security requirements | + +The specific assignment of roles and responsibilities is maintained in the ISMS tool ({{TOOL_NAME}}) or in a supplementary role matrix (see also {{LINK:R01}}). + +## 7. Binding nature + + + +This policy is approved by {{ROLE_MANAGEMENT}} and is binding for all affected persons within the scope. {{#if FLAG_INCLUDE_SHOULD}}Violations of information security requirements may lead to organisational, employment-law or contractual measures. {{/if}}All employees are obliged to: + +- comply with the applicable information security policies, +- handle information requiring protection appropriately, +- report security events or suspected cases without delay, +- use only approved systems, applications and services, +- report identified vulnerabilities or risks to the responsible body. + +## 8. Publication and communication + + + +The information security policy is made known to the relevant persons in a suitable form; employees and affected external partners are informed about relevant changes. This can be done via: + +- publication in the ISMS tool ({{TOOL_NAME}}), +- internal wiki or document management system, +- onboarding process, +- awareness training (see {{LINK:R05}}), +- direct communication to the affected target groups. + +## 9. Review and update + + +This policy is reviewed regularly, but at least: + +- {{REVIEW_CYCLE}}, +- upon material changes to the ISMS scope, +- upon material organisational or technical changes, +- in the event of relevant security incidents, +- upon new or changed regulatory, legal or contractual requirements. + +Changes are documented and approved by {{ROLE_MANAGEMENT}}. + +## 10. Evidence + +The evidence for the implementation of this policy is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 11. Related documents + + +Further topic-specific security policies (R01–R14) are established and coordinated with one another. + +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- ISMS organisation and roles: {{LINK:R01}} +- All thematic policies: {{LINK:R01}} … {{LINK:R14}} + + + + +{{#if FLAG_FW_ISO27001}} + +## Annex A — Information security policy, objectives and communication + +*Requirement reference:* ISO/IEC 27001 5.2, 6.2, 7.4, A.5.1 + +**Requirement** + + +- **[ISO 5.2]** An information security policy is established that fits the organisation, sets objectives, commits to meeting requirements and to continual improvement, and is communicated and available. + +- **[ISO 6.2]** Information security objectives are established for relevant functions and levels, and their achievement is planned. + +- **[ISO 7.4]** The internal and external communications relevant to the ISMS are determined. + +- **[ISO A.5.1]** The information security policy and topic-specific policies are defined, approved by management, published, communicated, acknowledged and reviewed at planned intervals. + +**Implementation at {{ORG_NAME}}** + + +This policy is approved by {{ROLE_MANAGEMENT}}, published in {{TOOL_NAME}} and made known to all staff and relevant third parties; acknowledgement is recorded per version. It is reviewed at least {{POLICY_REVIEW_CYCLE}} and upon significant change (BL-GOV-03). The thematic policies and the procedures elaborate it and follow the same approval and review cycle. The information security objectives are stated in measurable terms and held in {{TOOL_NAME}} with target value, responsible role and due date; their achievement is evaluated {{MGMT_REVIEW_CYCLE}}. For internal and external communication on information security it is defined what is communicated, when, with whom and by whom; the central point of contact is {{ROLE_ISB}}. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/P01_Prototypenschutz.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/P01_Prototypenschutz.md new file mode 100644 index 0000000..143a289 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/P01_Prototypenschutz.md @@ -0,0 +1,60 @@ +# Policy Prototype Protection + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the protection of prototypes and development objects requiring protection (assessment objective prototype protection, VDA ISA chapter 8). It elaborates the information security policy ({{LINK:L00}}) and is operationalised by the procedure {{LINK:VA-20}}. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}), insofar as prototypes or development objects requiring protection are processed, stored or transported. + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA, chapter 8) and **Implementation at {{ORG_NAME}}**. + +{{#if FLAG_PROTOTYPE_PROTECTION}} +### 3.1 Physical security and perimeter (ISA 8.1.1) + +**Requirement** + + +- **[MUST]** Areas in which prototypes are processed or stored are protected by defined security zones and an effective perimeter. + +**Implementation at {{ORG_NAME}}** + +Prototype areas are designated as a dedicated security zone with access control, perimeter protection and logging. Access is limited to authorised persons. + +### 3.2 Confidentiality and classification (ISA 8.2.1) + +**Requirement** + + +- **[MUST]** Confidentiality obligations exist for prototypes; the associated information is classified and labelled accordingly. + +**Implementation at {{ORG_NAME}}** + +All persons involved with prototypes (internal and external) sign confidentiality agreements. Prototypes and associated documents are classified as confidential or higher in accordance with the classification scheme. + +### 3.3 Transport and storage (ISA 8.3.1) + +**Requirement** + + +- **[MUST]** Transport and storage of prototypes are carried out according to documented protection requirements that ensure confidentiality and integrity. + +**Implementation at {{ORG_NAME}}** + +Transport and storage follow the procedure {{LINK:VA-20}}: secured containers, logged handovers, access and visual protection as well as traceability. +{{/if}} diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R01_ISMS-Organisation-und-Rollen.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R01_ISMS-Organisation-und-Rollen.md new file mode 100644 index 0000000..613f88f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R01_ISMS-Organisation-und-Rollen.md @@ -0,0 +1,294 @@ +# Policy ISMS Organisation and Roles + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the structure, steering and responsibilities of the ISMS of {{ORG_NAME}} as well as the consideration of information security in projects. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Steering of information security + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.2.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 5.1, A.5.4{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The scope of the ISMS (the organisation governed by the ISMS) is defined. + +- **[MUST]** The organisation's requirements for the ISMS are determined. + +- **[MUST]** The organisation's management has commissioned and approved the ISMS. + +- **[MUST]** The ISMS provides management with suitable means for monitoring and steering (e.g. management review). + +- **[MUST]** The applicable controls are determined (e.g. ISO 27001 statement of applicability or a completed ISA catalogue). + +- **[MUST]** The effectiveness of the ISMS is reviewed regularly by management. +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO 5.1]** Top management demonstrates leadership and commitment with respect to the ISMS. + +- **[ISO A.5.4]** Management requires all personnel to apply information security in accordance with the established requirements. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The ISMS scope, the requirements and the applicable controls (statement of applicability / ISA catalogue) are documented in the ISMS tool ({{TOOL_NAME}}). {{ROLE_MANAGEMENT}} has commissioned and approved the ISMS by management decision, provides resources and reviews its effectiveness at least {{REVIEW_CYCLE}} in a documented management review; operational steering rests with {{ROLE_ISB}}. + +### 3.2 Organisation of information security + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.2.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 5.3, 7.1, A.5.2, A.5.3{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Responsibilities for information security are defined, documented and assigned. + +- **[MUST]** The responsible employees are defined, qualified and enabled for their task. + +- **[MUST]** The necessary resources are available. + +- **[MUST]** The points of contact are known within the organisation and to relevant business partners. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** An appropriate information security structure within the organisation is defined and documented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Security-relevant roles that are not part of the ISMS but are relevant to information security are taken into account. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** An appropriate organisational separation of responsibilities is established to avoid conflicts of interest (segregation of duties). (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO 5.3]** Responsibilities and authorities for security-relevant roles are assigned and communicated. + +- **[ISO 7.1]** The resources needed for the ISMS are determined and provided. + +- **[ISO A.5.2]** Information security roles and responsibilities are defined and allocated. + +- **[ISO A.5.3]** Conflicting duties and areas of responsibility are segregated to reduce unauthorised or unintentional modification and misuse. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Responsibilities are documented in the role/responsibility matrix and in the ISMS tool ({{TOOL_NAME}}) and made known to the role holders as well as to relevant business partners. The role {{ROLE_ISB}} is appointed, qualified, equipped with resources and authority, and reports directly to {{ROLE_MANAGEMENT}}. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, an organisational segregation of duties (e.g. implementation vs. control) is established; unavoidable dual roles are safeguarded by compensating controls (four-eyes principle). +{{/if}} + +### 3.3 Information security in projects + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.2.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.8{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Projects are classified taking information security requirements into account. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Procedures and criteria for classifying projects are documented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A risk assessment following the defined procedure is carried out in an early project phase and repeated upon project changes. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Measures are derived for identified information security risks and taken into account in the project. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The derived measures are reviewed regularly during the project and reassessed when the assessment criteria change. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.8]** Information security is integrated into project management. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +At the outset, projects are classified with regard to their information security needs on the basis of the documented catalogue of criteria (BL-PROJ-01); classification, risk assessment and derived measures are maintained in the project register ({{LINK:REG-PROJECTS}}). In an early project phase and upon changes, a risk assessment is carried out following the procedure Information Security in Projects ({{LINK:VA-19}}); measures are tracked as tasks in {{TOOL_TICKET}} and reviewed before project completion. The project management is responsible; where the protection need is elevated, {{ROLE_ISB}} is involved. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, the derived measures are reviewed continuously over the course of the project and reassessed when the assessment criteria change. +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_MANAGEMENT}} | Commissioning, overall responsibility, management review | +| {{ROLE_ISB}} | Operational steering of the ISMS | +| {{ROLE_IT_LEAD}} | Technical implementation | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:L00}}, {{LINK:R03}}, {{LINK:R13}} + + + +{{#if FLAG_FW_ISO27001}} + +### 3.4 Context, interested parties and scope of the ISMS + +*Requirement reference:* ISO/IEC 27001 4.1, 4.2, 4.3, 4.4 + +**Requirement** + + +- **[ISO 4.1]** Internal and external issues that affect the ability to achieve the ISMS objectives are determined and kept up to date. + +- **[ISO 4.2]** The interested parties relevant to the ISMS and their information security requirements are determined. + +- **[ISO 4.3]** The scope of the ISMS is determined considering the issues, requirements and interfaces, and maintained as documented information. + +- **[ISO 4.4]** An ISMS is established, implemented, maintained and continually improved. + +**Implementation at {{ORG_NAME}}** + + +Internal and external issues as well as the relevant interested parties and their requirements are maintained in {{TOOL_NAME}} as a context and stakeholder analysis and updated at least {{POLICY_REVIEW_CYCLE}} and upon significant change. The scope of the ISMS ({{ISMS_SCOPE}}) is documented information and names sites, processes, organisational units and IT services as well as interfaces and dependencies on third parties; exclusions are justified. The ISMS is operated according to the PDCA cycle and continually improved. Responsible: {{ROLE_ISB}}; approval: {{ROLE_MANAGEMENT}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.5 Planning of changes to the ISMS + +*Requirement reference:* ISO/IEC 27001 6.3 + +**Requirement** + + +- **[ISO 6.3]** Changes to the ISMS are carried out in a planned manner. + +**Implementation at {{ORG_NAME}}** + + +Changes to the ISMS — scope, organisation, roles, key processes or systems — are planned, assessed before implementation and documented in {{TOOL_NAME}}. The assessment covers the purpose and potential consequences of the change, effects on risks and controls, the resources required and the assignment of responsibilities. Approval is given by {{ROLE_MANAGEMENT}}; technical changes additionally run through change management (BL-OPS-09, see {{LINK:VA-04}}). + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.6 Control of documented information + +*Requirement reference:* ISO/IEC 27001 7.5.1, 7.5.2, 7.5.3 + +**Requirement** + + +- **[ISO 7.5.1]** The ISMS includes the documented information required by the standard and that determined as necessary. + +- **[ISO 7.5.2]** When creating and updating documented information, identification, format and medium as well as review and approval are ensured. + +- **[ISO 7.5.3]** Documented information is controlled: availability, protection, distribution, access, retention and change control. + +**Implementation at {{ORG_NAME}}** + + +The documented information of the ISMS is maintained in {{TOOL_NAME}}. Every document carries a title, a unique identifier, version, date, status, responsible role and approver; creation and modification pass through review and four-eyes approval (BL-GOV-03). Control ensures availability to the authorised roles, protection against unauthorised modification, managed distribution, version control with a change history and retention of superseded versions ({{RECORDS_RETENTION}}). Documents of external origin are identified and controlled in the same way. Review cycle: {{POLICY_REVIEW_CYCLE}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.7 Contact with authorities and interest groups + +*Requirement reference:* ISO/IEC 27001 A.5.5, A.5.6 + +**Requirement** + + +- **[ISO A.5.5]** Appropriate contacts with relevant authorities are established and maintained. + +- **[ISO A.5.6]** Appropriate contacts with special interest groups, professional forums and security associations are maintained. + +**Implementation at {{ORG_NAME}}** + + +{{ROLE_ISB}} maintains a contact list of the relevant authorities and reporting bodies ({{AUTHORITY_CONTACTS}}) with responsibility, availability and reporting channel; it is checked for currency {{POLICY_REVIEW_CYCLE}} and is available in an emergency without IT access. Reporting obligations and deadlines are held in the incident procedure ({{LINK:VA-01}}). In addition, professional contacts with interest groups, forums and security associations are maintained; the resulting insights feed into the evaluation of threat intelligence. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md new file mode 100644 index 0000000..f2c77e6 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md @@ -0,0 +1,259 @@ +# Policy Asset and Classification Policy + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the identification, classification and protected handling of information assets as well as the approval of hardware and software. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Identification of information assets + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.9{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The organisation's information assets and other security-relevant assets are identified and recorded. + +- **[MUST]** The supporting assets that process the information assets are identified and recorded. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A catalogue of the relevant information assets exists; the relevant aspects are taken into account. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.9]** An inventory of information and associated assets, including owners, is established and maintained. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Information assets and supporting assets are recorded in the ISMS tool ({{TOOL_NAME}}) in the asset inventory with attributes (owner, location, protection need) and maintained as a catalogue (see {{LINK:VA-08}}); additions and removals are triggered via {{TOOL_TICKET}}. + +### 3.2 Classification of information assets + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.12, A.5.13{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** A consistent scheme for classifying information assets with regard to the protection goal of confidentiality is in place. + +- **[MUST]** The identified information assets are assessed according to the defined criteria and assigned to the classification scheme. + +- **[MUST]** Requirements for handling supporting assets (e.g. labelling, use, transport, storage, return, deletion/destruction) depending on the classification are in place and implemented. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The protection goals of integrity and availability are taken into account. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.12]** Information is classified according to its protection needs (confidentiality, integrity, availability). + +- **[ISO A.5.13]** Procedures for labelling information in accordance with the classification scheme are developed and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +A consistent four-tier classification scheme (Public / Internal / Confidential / Strictly confidential) applies for confidentiality; the classification is carried out according to defined criteria by the asset owner in the ISMS tool and also takes integrity and availability into account. Handling requirements per protection class (labelling, storage, transport, transmission BL-CRY-01/04, deletion BL-DEL-01) are defined, implemented and made known (see {{LINK:VA-08}}). + +### 3.3 Use of approved external IT services/hardware + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.10{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** External IT services are not used without an explicit assessment and implementation of the information security requirements; the relevant aspects are taken into account. + +- **[MUST]** The external IT services are aligned with the protection need of the information assets processed. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Requirements for procurement, commissioning and approval in connection with the use of external IT services are determined and met. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A procedure for approval taking the protection need into account is established. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** External IT services and their approval are documented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** It is regularly verified that only approved external IT services are used. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.10]** Rules for the acceptable use and handling of information and assets are defined, documented and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +External IT services/components are assessed before use, aligned with the protection need and approved via a defined procedure; the approvals are maintained in the register of external IT/cloud/AI services ({{LINK:REG-EXT-SERVICES}}) (supplier {{LINK:VA-10}}, asset {{LINK:VA-08}}) and regularly checked for exclusive use of approved services. + +### 3.4 Approval of software + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.19{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Software is approved before installation or use; the relevant aspects are taken into account. + +- **[MUST]** The software approval also applies to special software such as maintenance tools. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The types of software to be managed (firmware, operating systems, applications, libraries, device drivers) are determined. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Repositories of the managed software exist. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The software repositories are protected against unauthorised manipulation. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The approval of software is reviewed regularly. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Software versions and patch levels are known. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Additional requirements for software use (e.g. the need to control/monitor use) are determined where present. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.19]** Procedures and measures for securely managing software installation on operational systems are implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Software (incl. special/maintenance software) is approved before use; approved software is maintained in the software whitelist register ({{LINK:REG-SW-WHITELIST}}) with version/patch level, source/supplier ({{LINK:VA-10}}) and approval status and is linked to the asset inventory ({{LINK:VA-08}}); procurement/approval runs via {{TOOL_TICKET}}. Managed software types are determined, repositories protected against manipulation, and approvals are reviewed regularly. + +{{#if FLAG_ELEVATED_PROTECTION}} + +{{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, additional control/monitoring requirements for software use are determined and implemented.{{/if}} +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_IT_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Asset inventory, approval of hardware/software | +| {{ROLE_ISB}} | Classification scheme | +| Asset owner | Maintenance of individual assets | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_IT_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-08}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R01}}, {{LINK:R08}}, {{LINK:R11}} + + + +{{#if FLAG_FW_ISO27001}} + +### 3.5 Data masking and pseudonymisation + +*Requirement reference:* ISO/IEC 27001 A.8.11 + +**Requirement** + + +- **[ISO A.8.11]** Data masking is applied in accordance with the access control and privacy requirements. + +**Implementation at {{ORG_NAME}}** + + +Where the full information content is not required for the purpose, data is masked, pseudonymised or anonymised. This applies in particular to test, training and development environments ({{LINK:R11}}), to analyses and to displays with a restricted need for access. Extent and method follow the classification and the data protection requirements ({{LINK:R14}}); whether the link to a person may be restored, and how that is safeguarded, is governed explicitly. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md new file mode 100644 index 0000000..ae6af14 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md @@ -0,0 +1,289 @@ +# Policy Risk Management and Audit Policy + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the identification, assessment and treatment of information security risks as well as internal and independent reviews. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Risk management + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.4.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 6.1.1, 6.1.2, 8.2, 8.3{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Risk assessments are carried out regularly and on an ad-hoc basis. + +- **[MUST]** Information security risks are assessed appropriately (e.g. likelihood of occurrence and potential extent of damage). + +- **[MUST]** Information security risks are documented. + +- **[MUST]** A responsible person (risk owner) is assigned to each information security risk and is responsible for its assessment and treatment. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A procedure for the identification, assessment and treatment of security risks is in place. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Criteria for the assessment and treatment of security risks exist. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Risk treatment measures and their responsible persons are defined and documented; a measures plan or implementation overview is tracked. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Upon changes in the environment (e.g. organisational structure, location, regulations), a reassessment is carried out promptly. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO 6.1.1]** When planning the ISMS, risks and opportunities that need to be addressed are determined. + +- **[ISO 6.1.2]** A risk assessment process with defined criteria is established and applied so that it is repeatable and produces comparable results. + +- **[ISO 8.2]** Risk assessments are performed at planned intervals and upon significant change, and are documented. + +- **[ISO 8.3]** The risk treatment plan is implemented and the results are documented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The documented risk management procedure (see {{LINK:VA-09}}) with assessment and acceptance criteria is implemented in the ISMS tool ({{TOOL_NAME}}): risks are identified regularly ({{REVIEW_CYCLE}}) and on an ad-hoc basis, assessed (likelihood × impact) and documented; for each risk, a risk owner, treatment option and measures with deadlines are recorded and tracked. Residual risks are accepted by {{ROLE_MANAGEMENT}} in a documented manner. + +### 3.2 Verification of compliance in IS operations + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.5.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.36{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Compliance with the policies is reviewed organisation-wide. + +- **[MUST]** Information security policies and procedures are reviewed regularly. + +- **[MUST]** Measures to correct possible deviations are initiated and tracked. + +- **[MUST]** Compliance with information security requirements (e.g. technical specifications) is reviewed regularly. + +- **[MUST]** The results of the reviews carried out are recorded and retained. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A plan for the content and framework conditions (schedule, scope, controls) of the reviews to be carried out is in place. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.36]** Compliance with the information security policy, topic-specific policies, rules and standards is reviewed regularly. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Compliance with policies, procedures and technical requirements is reviewed organisation-wide and regularly according to the audit programme ({{LINK:REG-AUDIT-PLAN}}) and the audit/compliance review procedure ({{LINK:VA-15}}) through internal audits and controls (cycle BL-GOV-01); results are recorded and retained, deviations are tracked as measures in {{TOOL_NAME}}; responsible: {{ROLE_ISB}}. + +### 3.3 Independent review of the ISMS + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.5.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 9.2, A.5.35{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Information security reviews are carried out by an independent and competent body regularly and after fundamental changes. + +- **[MUST]** Measures to correct possible deviations are initiated and tracked. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The results of the reviews carried out are documented and reported to the organisation's management. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO 9.2]** Internal audits are conducted at planned intervals to verify conformity and effective implementation of the ISMS. + +- **[ISO A.5.35]** The organisation's approach to managing information security is reviewed independently at planned intervals. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The ISMS is reviewed regularly and after fundamental changes by an independent, competent body (internal audit or external auditing, e.g. TISAX); results are documented, reported to {{ROLE_MANAGEMENT}} and deviations tracked as measures. + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Risk management, audits | +| {{ROLE_MANAGEMENT}} | Risk acceptance | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-09}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R01}}, {{LINK:R04}} + + + +{{#if FLAG_FW_ISO27001}} + +### 3.4 Statement of Applicability (SoA) + +*Requirement reference:* ISO/IEC 27001 6.1.3 + +**Requirement** + + +- **[ISO 6.1.3]** A risk treatment process is defined; necessary controls are determined and compared against Annex A in a Statement of Applicability. + +**Implementation at {{ORG_NAME}}** + + +The risk treatment determines which controls are necessary; the result is compared against Annex A to identify controls that may have been overlooked. The Statement of Applicability is maintained in {{TOOL_NAME}} and states for each control: applicability, justification for inclusion, origin (risk ID, legal or contractual requirement), implementation status, responsible role, reference to policy and procedure as well as evidence; where a control is excluded, the justification is documented. The risk treatment plan and the acceptance of residual risks are approved by the respective risk owners; the SoA is approved by {{ROLE_MANAGEMENT}} and updated with every risk assessment ({{RISK_REVIEW_CYCLE}}). + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.5 Operational planning and control + +*Requirement reference:* ISO/IEC 27001 8.1 + +**Requirement** + + +- **[ISO 8.1]** The processes needed to meet the requirements are planned, implemented and controlled; planned changes are controlled. + +**Implementation at {{ORG_NAME}}** + + +The processes required to meet the information security requirements are laid down in the procedures and controlled in {{TOOL_NAME}}; for each process the trigger, responsible role, deadlines and evidence are defined. Planned changes are controlled and their consequences assessed; unintended changes are reviewed and corrected where necessary. Outsourced processes are determined and monitored through supplier management ({{LINK:R13}}). Evidence of execution as planned is kept in the evidence register ({{LINK:NACHWEISREGISTER}}). + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.6 Monitoring, measurement, analysis and evaluation + +*Requirement reference:* ISO/IEC 27001 9.1 + +**Requirement** + + +- **[ISO 9.1]** The information security performance and the effectiveness of the ISMS are monitored, measured, analysed and evaluated. + +**Implementation at {{ORG_NAME}}** + + +For the evaluation of information security performance and the effectiveness of the ISMS it is defined what is measured (metrics sheet in {{TOOL_NAME}}), by which method and data source, at which interval, who measures, when the results are analysed and who analyses them. The metrics cover at least incident handling, vulnerability and patch remediation, recertification of access rights, restore tests, awareness participation and open actions; each metric has a target value and a responsible role. Results and trends feed into the management review {{MGMT_REVIEW_CYCLE}}; a deviation from the target value triggers an action. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.7 Management review + +*Requirement reference:* ISO/IEC 27001 9.3 + +**Requirement** + + +- **[ISO 9.3]** Top management reviews the ISMS at planned intervals. + +**Implementation at {{ORG_NAME}}** + + +{{ROLE_MANAGEMENT}} reviews the ISMS at least {{MGMT_REVIEW_CYCLE}} against a fixed agenda (BL-GOV-02). Inputs are at least: status of actions from previous reviews; changes in relevant internal and external issues and in the requirements of interested parties; feedback on information security performance (nonconformities and corrective actions, monitoring and measurement results, audit results, achievement of the information security objectives); feedback from interested parties; results of the risk assessment and status of the risk treatment plan; opportunities for improvement. Outputs are decisions on opportunities for improvement and on any need to change the ISMS, each with a responsible role and a due date. The minutes are retained in {{TOOL_NAME}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.8 Nonconformity, corrective action and continual improvement + +*Requirement reference:* ISO/IEC 27001 10.1, 10.2 + +**Requirement** + + +- **[ISO 10.1]** The suitability, adequacy and effectiveness of the ISMS are continually improved. + +- **[ISO 10.2]** In the event of nonconformity, corrections are made and corrective actions are taken to eliminate the causes. + +**Implementation at {{ORG_NAME}}** + + +Nonconformities arising from audits, controls, incidents, deviations of metrics and reports are recorded in {{TOOL_NAME}}. For each case the immediate correction and the handling of the consequences are decided, the cause is analysed and it is evaluated whether similar nonconformities exist or could occur elsewhere. Necessary corrective actions are implemented with a responsible role and a due date; their effectiveness is evaluated after the defined effectiveness interval and, where necessary, risks, controls and documents are adjusted. The nature of the nonconformity, the actions taken and the result of the effectiveness review are retained. The suitability, adequacy and effectiveness of the ISMS are continually improved; evidence is provided through metrics and the management review. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md new file mode 100644 index 0000000..ced271d --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md @@ -0,0 +1,383 @@ +# Policy Incident, Emergency and Continuity Policy + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the reporting and handling of security events, crisis management as well as emergency and continuity planning. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Reporting of security events + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.6.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.24, A.6.8{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** A definition of a reportable security event or observation exists and is known to employees and relevant stakeholders. + +- **[MUST]** Appropriate, risk-oriented mechanisms for reporting security events are defined, implemented and known to all relevant reporters. + +- **[MUST]** Appropriate channels for communicating with reporters exist. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A common point of contact for event reporting exists. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Different reporting channels depending on the perceived severity (real-time for serious events/emergencies as well as asynchronous mechanisms such as tickets or email) are available. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Employees are obliged and trained to report relevant events. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Security events can also be reported by external parties; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The mechanism and the information on how incidents are reported are accessible to all relevant reporters. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A feedback procedure to the reporters is established. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Tests and exercises of event and observation reporting are carried out regularly. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.24]** The management of information security incidents is planned and prepared (roles, processes, responsibilities). + +- **[ISO A.6.8]** A mechanism for the timely reporting of observed or suspected information security events is provided. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +A known definition of reportable events and a low-threshold reporting path (report button/form in {{TOOL_TICKET}} or the ISMS tool, email to {{ROLE_ISB}}, real-time channel for serious cases) are available to all employees and external parties; the reporting path is known via onboarding/awareness (BL-HR-01), and a feedback procedure is established (see {{LINK:VA-01}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +{{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, tests and exercises of event reporting are carried out regularly.{{/if}} +{{/if}} + +### 3.2 Handling of security events + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.6.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.25, A.5.26, A.5.27, A.5.28{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Reported events are processed without undue delay. + +- **[MUST]** An appropriate response to reported security events is ensured. + +- **[MUST]** Lessons learned feed into continual improvement. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** During processing, reported events are categorised (e.g. personnel, physical, cyber), qualified (e.g. not security-relevant, observation, improvement suggestion, vulnerability, incident) and prioritised (e.g. low, medium, high, critical). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Responsibilities for handling events per category are defined and assigned. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A strategy for reporting potentially criminally relevant aspects to the competent authorities, where necessary, exists. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Maximum response times per class, category and severity are defined. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Events not processed in line with their priority are escalated; the relevant aspects are taken into account. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Legal, regulatory and contractual reporting obligations and the associated contact information are known. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** A communication strategy for security-relevant events exists; the relevant aspects are taken into account. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Procedures for responding to security incidents at suppliers are established; the relevant aspects are taken into account. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** The handling of events of different categories and priorities is tested regularly; the relevant aspects are taken into account. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.25]** Information security events are assessed and a decision is taken whether they are to be categorised as incidents. + +- **[ISO A.5.26]** Information security incidents are responded to in accordance with documented procedures. + +- **[ISO A.5.27]** Knowledge gained from information security incidents is used to strengthen the controls. + +- **[ISO A.5.28]** Procedures for the identification, collection, acquisition and preservation of evidence relating to incidents are established and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Events are categorised, qualified, prioritised, handled and documented without delay following a defined incident procedure (see {{LINK:VA-01}}) in {{TOOL_TICKET}}; responsibilities and escalation paths are assigned ({{ROLE_ISB}} coordinates, {{ROLE_IT_LEAD}} implements). Lessons learned feed into improvement; a strategy for reporting to authorities/law enforcement exists. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, maximum response times per severity are defined, escalations for events not processed in line with their priority are regulated, reporting obligations and contacts are known, and a communication strategy as well as a procedure for supplier incidents are established. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, event handling is tested regularly.{{/if}} +{{/if}} + +### 3.3 Crisis management + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 1.6.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.29{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** An appropriate plan for responding to and managing crisis situations exists and the necessary resources are available. + +- **[MUST]** Responsibilities and authorities for crisis management are defined, documented and assigned. + +- **[MUST]** The responsible employees are defined and qualified for their task. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Methods for detecting crisis situations are established; general indicators and specific foreseeable crises are identified. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A procedure for triggering and/or escalating crisis management is in place. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Strategic objectives and their priority in crisis situations are defined and known to relevant personnel. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A crisis team is defined and approved. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Crisis policies and procedures are defined and approved. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The crisis planning is reviewed and updated regularly. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Relevant different potential crisis scenarios are identified. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The resources and information necessary for crisis management (e.g. communication infrastructure, availability of contact and risk information) are identified; appropriate measures to ensure availability or fallback planning are in place. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** A communication strategy for crisis situations exists. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The efficiency, feasibility and appropriateness of the crisis planning are assessed regularly. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Sample-based tests of the crisis planning are carried out (e.g. simulation, tabletop exercises with key personnel). (A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Crisis exercises and simulations involving all relevant persons, including decision-makers, are carried out regularly. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.29]** The maintenance of information security during disruption is planned and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +A crisis management with a plan, a defined and approved crisis team, roles, triggering/escalation, communication and decision paths as well as strategic objectives is established (triggering/recovery see {{LINK:VA-02}}); the necessary resources are available and the responsible persons are qualified. Detection methods are in place, the crisis planning is reviewed and updated regularly; the crisis team is convened by {{ROLE_MANAGEMENT}}. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, relevant crisis scenarios are identified, the necessary resources/information and a communication strategy are ensured, and the planning is assessed regularly and tested on a sample basis (tabletop). {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, crisis exercises involving all relevant persons including decision-makers are carried out regularly.{{/if}} +{{/if}} + +### 3.4 Continuity planning for IT services + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.8{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.30, A.8.14{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Critical IT services are identified and the business impact is taken into account. + +- **[MUST]** Requirements and responsibilities for the continuity and recovery of these IT services are known to relevant stakeholders and fulfilled. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Critical IT systems are identified; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A continuity plan exists and is reviewed and updated regularly. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The continuity planning covers at least (D)DoS attacks, successful ransomware attacks and other sabotage, system failure scenarios as well as natural disasters affecting critical IT systems. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The continuity planning contains predefined time frames (recovery time objective) for the resumption of operations. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Appropriate SLAs with external service providers in line with the continuity planning are in place. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The continuity plans include the coordination of contractually agreed communication with business partners. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The continuity planning is tested regularly, incl. full recovery to a known state and adherence to defined target times. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** A backup and recovery strategy for critical IT services and information is defined and implemented. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Backups of critical IT services and information are sufficiently protected against unauthorised modification/deletion by malware. (I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Backups of critical IT services and information are sufficiently protected against unauthorised access by malware or operators. (C, I) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** The continuity planning is coordinated with the continuity plans of relevant external service providers. (A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** The continuation of essential core and business functions with minimal or no loss of operational continuity is possible; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** The continuity planning is tested regularly. Test scenarios, results and lessons learned are recorded. (I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.30]** ICT readiness is planned, implemented and tested on the basis of the business continuity objectives and requirements. + +- **[ISO A.8.14]** Information processing facilities are implemented with sufficient redundancy to meet the availability requirements. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Critical IT services are recorded with their business impact in the register of critical IT services ({{LINK:REG-CRIT-SERVICES}}) (incl. BIA classification, RTO/RPO, recovery sequence); requirements and responsibilities for continuity/recovery are known and fulfilled. A continuity plan (incl. (D)DoS, ransomware, failure, natural disasters) exists, is reviewed regularly and implemented via the IT emergency procedure (see {{LINK:VA-02}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, RTO/RPO, SLAs with service providers, partner communication, regular full tests as well as a protected backup/recovery strategy (immutable/isolated) are established. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, the planning is coordinated with external service providers, the continuation of essential functions is ensured, and tests incl. lessons learned are recorded.{{/if}} +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Incident coordination | +| {{ROLE_IT_LEAD}} | Emergency/recovery planning | +| {{ROLE_MANAGEMENT}} | Crisis team | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-01}}, {{LINK:VA-02}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R03}}, {{LINK:R10}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R05_Personalsicherheit-und-Awareness.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R05_Personalsicherheit-und-Awareness.md new file mode 100644 index 0000000..f3775b8 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R05_Personalsicherheit-und-Awareness.md @@ -0,0 +1,221 @@ +# Policy Personnel Security and Awareness + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_HR_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs the suitability, contractual commitment as well as training and awareness of personnel. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Qualification for sensitive activities + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 7.2, A.6.1{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Sensitive work areas and activities are determined. + +- **[MUST]** The requirements for employees with regard to their job profiles are determined and met. + +- **[MUST]** The identity of potential employees is verified (e.g. checking of identity documents). +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The personal suitability of potential employees is checked using simple methods (e.g. job interview). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** An extended suitability check depending on the work area and the activity is carried out (e.g. assessment centre, checking of references, certificates and criminal record certificates). +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO 7.2]** The necessary competence is determined and ensured; corresponding evidence is retained. + +- **[ISO A.6.1]** Background verification of candidates is carried out appropriately to the business requirements and in accordance with the law. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Sensitive work areas and activities are determined in the register of sensitive activities ({{LINK:REG-SENS-ROLES}}) and recorded with the required depth of checking; requirements for positions are documented in job descriptions and are met. Identity verification as well as the personal and — for sensitive roles — extended suitability check (interview, references, criminal record certificate within the legally permissible scope) are carried out following the suitability and verification procedure ({{LINK:VA-14}}); responsible: {{ROLE_HR_LEAD}}; evidence in the personnel file. + +### 3.2 Contractual commitment of personnel + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.6.2, A.6.5, A.6.6{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** A confidentiality obligation is in force. + +- **[MUST]** An obligation to comply with the information security policies is in force. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A confidentiality obligation going beyond the employment contract is in force. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Information security aspects are taken into account in the employees' employment contracts. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A procedure for dealing with violations of these obligations is described. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.6.2]** The employment agreements state the responsibilities for information security. + +- **[ISO A.6.5]** Continuing information security responsibilities after termination or change of employment are defined and enforced. + +- **[ISO A.6.6]** Confidentiality or non-disclosure agreements are identified, documented and reviewed regularly. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +All employees are contractually obliged upon joining to confidentiality and to compliance with the information security policies ({{ROLE_HR_LEAD}}); information security aspects are part of the employment contracts, and confidentiality continues to apply after termination. A documented procedure for dealing with violations (see {{LINK:VA-14}}) is established; the evidence is kept in the personnel file. + +### 3.3 Awareness and training + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 7.3, A.6.3{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Employees are trained and made aware. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A concept for the awareness and training of employees is created. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Target groups for training and awareness measures (e.g. managers, administrators, employees with access to customer networks, production personnel) are identified and taken into account in the concept. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The concept is approved by the responsible management. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Training and awareness measures are carried out regularly and on an ad-hoc basis. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Participation in training and awareness measures is documented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Points of contact for information security are known to the employees. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO 7.3]** Persons under the organisation's control are aware of the policy, their contribution and the consequences of non-conformance. + +- **[ISO A.6.3]** Personnel receive appropriate awareness, education and training as well as regular updates of the relevant policies. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +A role-specific training/awareness concept approved by management (BL-HR-01) is established; employees are trained upon joining and thereafter at least {{REVIEW_CYCLE}} and on an ad-hoc basis (process see {{LINK:VA-12}}). Target groups are identified, records of participation are kept in {{TOOL_NAME}}, points of contact for information security are known; the effectiveness is checked (e.g. phishing simulation). + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_HR_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_HR_LEAD}} | Commitment, suitability | +| {{ROLE_ISB}} | Awareness/training | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_HR_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-12}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R01}}, {{LINK:R06}} + + + +{{#if FLAG_FW_ISO27001}} + +### 3.4 Handling of violations + +*Requirement reference:* ISO/IEC 27001 A.6.4 + +**Requirement** + + +- **[ISO A.6.4]** A disciplinary process for information security violations is established and communicated. + +**Implementation at {{ORG_NAME}}** + + +A graduated, documented process applies to violations of the information security requirements and is communicated in advance. It takes into account the nature and severity of the violation, intent or negligence, repetition and the training status of the person concerned. The process is run by {{ROLE_HR_LEAD}} in coordination with {{ROLE_ISB}}; employment law requirements and co-determination rights are observed. Its application is documented confidentially. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md new file mode 100644 index 0000000..1fd6202 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md @@ -0,0 +1,151 @@ +# Policy Mobile Working and Mobile Devices + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs mobile working as well as the handling of mobile IT devices and data media. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +{{#if FLAG_MOBILE_WORK}} +### 3.1 Mobile working + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.6.7{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The requirements for mobile working are determined and met; the relevant aspects are taken into account. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The relevant aspects of mobile working are taken into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Awareness of employees. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Protective measures against eavesdropping and being overlooked are implemented. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.6.7]** Security measures for working outside the organisation's premises are implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Mobile working is defined in this policy and the associated mobile working rule (stored in {{TOOL_NAME}}) and the requirements are met; access is exclusively via {{TECH_VPN}} with MFA (BL-IAM-02) and approved, encrypted devices (BL-CRY-03). Employees are made aware (BL-HR-01). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, protective measures against eavesdropping and being overlooked are implemented (e.g. privacy screen, quiet environment, clean screen). +{{/if}} + +{{/if}} +{{#if FLAG_MOBILE_DEVICES}} +### 3.2 Mobile IT devices and data media + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 3.1.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.7.9, A.7.10, A.8.1{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The requirements for mobile IT devices and mobile data media are determined and met; the relevant aspects are taken into account. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Registration of the IT devices. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** General encryption of mobile data media or of the information assets stored on them. Where technically not feasible, information is protected by equivalent measures. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.7.9]** Assets used outside the premises are protected. + +- **[ISO A.7.10]** Storage media are protected throughout their life cycle (acquisition, use, transport, disposal) in accordance with the classification scheme. + +- **[ISO A.8.1]** Information stored on, processed by or accessible via user endpoint devices is protected. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The requirements for mobile devices and data media are determined and met: devices are registered and centrally managed via {{TECH_MDM}}, only approved devices are used; loss is reported via the reporting path (R04) and {{TOOL_TICKET}}, blocking/wiping upon loss via {{TECH_MDM}} (BL-EP-02). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, mobile data media or the information stored on them are generally encrypted (BL-CRY-03); where not feasible, equivalent protective measures apply. +{{/if}} + +{{/if}} +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Security requirements | +| {{ROLE_IT_LEAD}} | Technical implementation | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R05}}, {{LINK:R07}}, {{LINK:R08}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R07_Physische-Sicherheit.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R07_Physische-Sicherheit.md new file mode 100644 index 0000000..fd427ba --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R07_Physische-Sicherheit.md @@ -0,0 +1,173 @@ +# Policy Physical Security + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs physical protection through security zones, access protection and the handling of supporting utilities. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Security zones and access + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 3.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.7.1, A.7.2, A.7.3, A.7.4, A.7.6{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** A security zone concept including associated protective measures based on the requirements for handling information assets is in place. + +- **[MUST]** The defined protective measures are implemented. + +- **[MUST]** The code of conduct for security zones is known to all persons involved. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Procedures for granting and revoking access rights are established. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Policies for visitor management (including registration and escorting of visitors) are defined. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Policies for carrying and using mobile IT devices and data media (e.g. registration, labelling obligations) are defined and implemented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Network/infrastructure components (own or customer networks) are protected against unauthorised access. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** External premises used for storing/processing information assets are taken into account in the zone concept (e.g. storage rooms, workshops, test tracks, data centres). +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Protective measures against simple eavesdropping and being overlooked are implemented. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.7.1]** Security perimeters are defined and used to protect areas containing information and assets. + +- **[ISO A.7.2]** Secure entry controls and entry points are established to restrict access to authorised persons. + +- **[ISO A.7.3]** Physical security for offices, rooms and facilities is designed and implemented. + +- **[ISO A.7.4]** Premises are continuously monitored for unauthorised physical access. + +- **[ISO A.7.6]** Measures for working in secure areas are defined and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +A security zone concept (BL-PHY-01) with implemented protective measures and a known code of conduct is in place; access rights are granted on a needs-oriented basis via {{TOOL_TICKET}}, documented and revoked when no longer needed (BL-PHY-02, process see {{LINK:VA-17}}). Visitor management, rules for mobile devices, protection of network/infrastructure components and external premises are taken into account. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, additional protective measures against simple eavesdropping and being overlooked are implemented. +{{/if}} + + + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_IT_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Zones, access, utilities | +| {{ROLE_ISB}} | Specifications | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_IT_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R02}}, {{LINK:R06}} + + + +{{#if FLAG_FW_ISO27001}} + +### 3.2 Environmental protection, utilities, cabling and maintenance + +*Requirement reference:* ISO/IEC 27001 A.7.5, A.7.8, A.7.11, A.7.12, A.7.13 + +**Requirement** + + +- **[ISO A.7.5]** Protection against physical and environmental threats is designed and implemented. + +- **[ISO A.7.8]** Equipment is sited securely and protected. + +- **[ISO A.7.11]** Facilities are protected against failure and disruption of supporting utilities such as power and air conditioning. + +- **[ISO A.7.12]** Power and data cabling is protected against interception, interference and damage. + +- **[ISO A.7.13]** Equipment is maintained properly to ensure availability and integrity. + +**Implementation at {{ORG_NAME}}** + + +Sites and technical facilities are protected against physical and environmental threats (BL-PHY-03): early fire detection, protection against water and moisture, temperature and humidity monitoring in technical rooms as well as consideration of site-specific hazards. Equipment is sited so that observation, unauthorised access and environmental risks are minimised. Power and air conditioning for critical systems are designed to be uninterruptible and are tested regularly. Power and data cabling is protected against damage and unauthorised access and is documented. Equipment is maintained according to the manufacturer's specifications; maintenance is carried out only by authorised personnel, is planned and recorded, and is supervised where performed externally. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.3 Clear desk and screen lock + +*Requirement reference:* ISO/IEC 27001 A.7.7 + +**Requirement** + + +- **[ISO A.7.7]** Rules for a clear desk and locked screens are defined and implemented. + +**Implementation at {{ORG_NAME}}** + + +Binding rules apply for a clear desk and locked screens (BL-PHY-04): protected documents and media are locked away when unattended; screens are locked when leaving the workplace and lock automatically after {{SESSION_TIMEOUT}}. Printouts are collected immediately and documents no longer required are destroyed according to their protection needs (BL-DEL-01). The rules also apply when working from home and at mobile workplaces ({{LINK:R06}}); compliance is checked on a sample basis. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md new file mode 100644 index 0000000..e01a68d --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md @@ -0,0 +1,314 @@ +# Policy Identity and Access Management + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs means of identification, secure log-on, account management as well as the granting and control of access rights. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Handling of means of identification + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.16{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The requirements for handling means of identification throughout the entire lifecycle are determined and met; the relevant aspects are taken into account. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Means of identification can only be created under controlled conditions. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** A strategy for blocking or invalidating means of identification in the event of loss is prepared and, as far as possible, implemented. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.16]** The full life cycle of identities is managed. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Means of identification (user IDs, tokens, certificates) are assigned throughout the lifecycle uniquely to a person and under controlled conditions via the central directory ({{TOOL_IAM}}); issuance, withdrawal and blocking are requested, approved and documented in {{TOOL_TICKET}} (BL-IAM-07, see {{LINK:VA-03}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, an implemented strategy for blocking/invalidating means of identification in the event of loss is in place. +{{/if}} + +### 3.2 Secure log-on + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.5{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The user authentication procedures are selected on the basis of a risk assessment; possible attack scenarios (e.g. direct reachability via the internet) have been taken into account. + +- **[MUST]** State-of-the-art user authentication procedures are applied. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The authentication procedures are defined and implemented on the basis of business and security requirements. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Users are authenticated at least by strong passwords in line with established and recognised practices. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** For privileged user accounts, higher-grade procedures are used (e.g. privileged access management, two-factor authentication). +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Depending on the risk assessment, authentication and access control are strengthened by supplementary measures (e.g. continuous access monitoring, strong authentication, automatic log-off, lock upon inactivity, brute-force prevention). (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Before accessing data with a very high protection need, users are authenticated by means of strong authentication (e.g. two-factor) in line with the state of the art. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.5]** Secure authentication technologies and procedures are used on the basis of the access restrictions and the access control policy. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The authentication procedures are selected on a risk basis and correspond to the state of the art; password requirements per BL-IAM-01 (at least {{PW_MIN_LENGTH}} characters, {{PW_COMPLEXITY}}, {{PW_ROTATION}}) are enforced via the central directory ({{TOOL_IAM}}). For remote access, administrative access and cloud services, MFA (BL-IAM-02) is enforced via {{TECH_MFA}}; privileged accounts use higher-grade procedures (PAM). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, authentication/access control are strengthened by supplementary measures (access monitoring, auto-logout BL-IAM-03, lock BL-IAM-04, brute-force protection). {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, access is only granted after strong authentication (two-factor).{{/if}} +{{/if}} + +### 3.3 User accounts and log-on information + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.17{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The creation, modification and deletion of user accounts is carried out. + +- **[MUST]** Unique and personalised user accounts are used. + +- **[MUST]** The use of shared accounts is regulated (e.g. limited to cases where traceability is dispensable). + +- **[MUST]** User accounts are deactivated immediately after the user leaves (e.g. upon end of contract). + +- **[MUST]** User accounts are reviewed regularly. + +- **[MUST]** The log-on information is provided to the user in a secure manner. + +- **[MUST]** A policy for handling log-on information is defined and implemented; the relevant aspects are taken into account. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A base account with minimal access rights and functionalities exists and is used. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Default accounts and passwords preconfigured by the manufacturer are deactivated (e.g. blocking or password change). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** User accounts are created or authorised by the responsible body. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The creation of user accounts is subject to an approval process (four-eyes principle). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** User accounts of service providers are deactivated after completion of their task. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Deadlines for deactivating and deleting user accounts are defined. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The use of default passwords is prevented technically. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** In the case of strong authentication, the use of the medium (e.g. possession factor) is secure. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** User accounts are reviewed regularly; this also includes accounts in customers' IT systems. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Interactive log-on for service accounts (technical accounts) is prevented technically. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.17]** Allocation and management of authentication information is controlled by a suitable management process. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +User accounts are managed via a defined lifecycle (joiner/mover/leaver) (see {{LINK:VA-03}}) uniquely personalised in the central directory ({{TOOL_IAM}}); triggers are {{TOOL_TICKET}} requests from HR/manager notifications. Accounts of leavers are deactivated without delay, accounts are reviewed regularly (including in customer systems), shared accounts are regulated. Log-on information is provided securely; default accounts/passwords are deactivated, base accounts with minimal rights are used, creation follows the four-eyes principle, and interactive log-on for technical accounts is prevented. + +### 3.4 Access rights + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 4.2.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.15, A.5.18, A.8.2, A.8.3, A.8.18{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The requirements for managing access rights (authorisation) are determined and met; the relevant aspects are taken into account. + +- **[MUST]** The access rights granted for normal and privileged user accounts as well as technical accounts are reviewed regularly, also in customers' IT systems. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Strategies for authorising access to information are prepared. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Authorisation roles are used. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Rights are granted according to the need-to-use principle and in line with role and/or area of responsibility. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Normal user accounts do not receive privileged access rights. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The user's access rights are updated after a change in their responsibilities. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The access rights are approved by the responsible internal information officer. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Information is stored encrypted at content level (e.g. file level) to prevent unauthorised access (including by privileged users). Where encryption is not feasible, equivalent measures apply. (C) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Existing access rights are reviewed at shorter intervals (e.g. quarterly). (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.15]** Rules to control physical and logical access to information and assets are established and implemented on the basis of business and information security requirements. + +- **[ISO A.5.18]** Access rights are provisioned, reviewed, modified and removed in accordance with the access control policy. + +- **[ISO A.8.2]** The allocation and use of privileged access rights is restricted and closely managed. + +- **[ISO A.8.3]** Access to information and application functions is restricted in accordance with the access control policy. + +- **[ISO A.8.18]** The use of utility programs capable of overriding system and application controls is restricted and tightly controlled. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Access rights are granted according to the least-privilege principle (need-to-know/least privilege) on a role basis (RBAC) via the central directory ({{TOOL_IAM}}); request, technical review and approval take place in {{TOOL_TICKET}} (see {{LINK:VA-03}}). Rights are updated or revoked upon change/removal and recertified at least {{RECERT_FREQ}} (BL-IAM-05), also in customer systems; default accounts do not receive privileged rights. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, access rights are approved by the responsible internal information officer. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, information is stored with content-level encryption (protection also against privileged users) and access rights are reviewed at shorter intervals (e.g. quarterly).{{/if}} +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_IT_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Technical implementation of IAM | +| Business units | Approval of authorisations | +| {{ROLE_ISB}} | Monitoring | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_IT_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-03}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R02}}, {{LINK:R05}}, {{LINK:R10}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md new file mode 100644 index 0000000..e11ffcc --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md @@ -0,0 +1,156 @@ +# Policy Cryptography and Transmission Policy + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs cryptographic procedures, key management and protection during information transmission. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Use of cryptographic procedures + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.24{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** All cryptographic procedures used (e.g. encryption, signature, hash algorithms, protocols) provide the security required in the respective field of application according to a recognised industry standard, as far as legally possible. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A concept for the use of cryptography is defined and implemented; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Requirements for key sovereignty (in particular in the case of external processing) are determined and met. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.24]** Rules for the effective use of cryptography, including key management, are defined and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The permissible procedures and key lengths per BL-CRY-02 ({{CRYPTO_ALGO}}) correspond to the recognised industry standard and are prescribed; outdated procedures are prohibited. A cryptography concept is documented (see {{LINK:VA-07}}), and keys are securely managed throughout their lifecycle (BL-CRY-05). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, requirements for key sovereignty (in particular in the case of external processing) are determined and met. +{{/if}} + +### 3.2 Protection during information transmission + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.14{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The network services used for transmitting information are identified and documented. + +- **[MUST]** Policies and procedures in line with the classification requirements for the use of network services are defined and implemented. + +- **[MUST]** Measures to protect transmitted content against unauthorised access are implemented. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Measures to ensure correct addressing and correct transmission of information are implemented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Electronic data exchange takes place using content or transport encryption in line with the respective classification. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Remote access connections to the organisation's network have appropriate security features; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Information is transmitted encrypted (at least transport encryption) or protected by equivalently effective measures. (C) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Information is transmitted with content encryption. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.14]** Rules, procedures and agreements for the secure transfer of information are established for all transfer channels in use. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The network services used are identified and documented in the network/network services register ({{LINK:REG-NET}}); policies/procedures in line with the classification are implemented. Information is protected during transmission in accordance with the protection need (at least {{TLS_MIN}}, BL-CRY-01), correct addressing is ensured and remote access is safeguarded; rules for email/file encryption are defined (BL-CRY-04, cryptography/key management see {{LINK:VA-07}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, information is transmitted at least transport-encrypted or protected equivalently; {{#if FLAG_VERY_HIGH_PROTECTION}}where the protection need is very high, content encryption is applied.{{/if}} +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_IT_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Procedures/keys | +| {{ROLE_ISB}} | Permissible algorithms | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_IT_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-07}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R08}}, {{LINK:R10}}, {{LINK:R12}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R10_Betriebssicherheit.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R10_Betriebssicherheit.md new file mode 100644 index 0000000..87b63e6 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R10_Betriebssicherheit.md @@ -0,0 +1,598 @@ +# Policy Operational Security + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs secure IT operations: change, environment separation, malware protection, logging, vulnerabilities, technical review, network security as well as data backup. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Change management (change) + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.9, A.8.32{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Information security requirements for changes to the organisation, business processes and IT systems are determined and met. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A formal approval procedure is established. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The possible effects of changes on information security are assessed. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Changes with an effect on information security are planned and tested. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Fallback procedures in the event of errors are taken into account. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Compliance with the information security requirements is verified during and after the changes. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.9]** Configurations of hardware, software, services and networks are established, documented, implemented, monitored and reviewed. + +- **[ISO A.8.32]** Changes to information processing facilities and systems are subject to change management. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Changes go through a formal change procedure (see {{LINK:VA-04}}) with request, impact/risk assessment, planning, testing, approval, rollback plan and documentation in {{TOOL_TICKET}} (BL-OPS-09); information security requirements are determined and met. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, compliance with the information security requirements is verified during and after the change. +{{/if}} + +### 3.2 Separation of development, test and production systems + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.31{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The IT systems have been subjected to a risk assessment to determine the need to separate them into development, test and production systems. + +- **[MUST]** A segmentation is implemented on the basis of the results of the risk analysis. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The requirements for development and test environments are determined and met; the relevant aspects are taken into account. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.31]** Development, test and production environments are separated and protected. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +On the basis of a risk assessment, development, test and production are operated separately and segmented; requirements for development/test environments are determined and met, and production data is used there only in anonymised/pseudonymised form. + +### 3.3 Protection against malware + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.7, A.8.23{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Requirements for protection against malware are determined. + +- **[MUST]** Technical and organisational measures for protection against malware are defined and implemented. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Unnecessary network services are deactivated. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Access to network services is limited to what is necessary through appropriate protective measures. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Protective software against malware is installed and updated automatically at regular intervals (e.g. virus scanner). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Received files and software are automatically checked for malware before execution (on-access scan). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The entire data stock of all systems is checked for malware regularly. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Data transmitted via central gateways (e.g. email, internet, external networks) is automatically checked by protective software. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Measures preventing protective software from being deactivated or modified by users are defined and implemented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** For IT systems without protective software, alternative measures are implemented (e.g. special resilience, few services, no active users, network isolation). +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.7]** Protection against malware is implemented and supported by appropriate user awareness. + +- **[ISO A.8.23]** Access to external websites is managed to reduce exposure to malicious content. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Malware protection is implemented via {{TECH_MALWARE}} on all endpoints and servers (BL-OPS-03); signatures/engines update themselves {{MALWARE_UPDATE}}, on-access and regular full scans as well as gateway checks (email/internet) are active. Unnecessary network services are deactivated, access is limited, and deactivating the protective software is prevented; for systems without protective software, alternative measures apply (isolation). + +### 3.4 Logging and evaluation + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.15, A.8.16{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Information security requirements for handling event logs are determined and met. + +- **[MUST]** Security-relevant requirements for logging the activities of administrators and users are determined and met. + +- **[MUST]** The IT systems used are assessed with regard to the need for logging. + +- **[MUST]** When external IT services are used, information on the monitoring options is obtained and taken into account in the assessment. + +- **[MUST]** Event logs are checked regularly for policy violations and conspicuous problems, in compliance with the permissible legal and organisational requirements. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A procedure for escalating relevant events to the responsible body is defined and established. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Event logs (content and metadata) are protected against modification (e.g. by a dedicated environment). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Appropriate monitoring and recording of all information-security-relevant actions in the network is established. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Security-relevant requirements for handling event logs, e.g. contractual requirements, are determined and implemented. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Events relating to the establishment and termination of remote access sessions (e.g. remote maintenance) are logged. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Logging of every access to data with a very high protection need, as far as technically feasible and legally/organisationally permissible. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.15]** Logs of activities, exceptions, faults and events are produced, stored, protected and analysed. + +- **[ISO A.8.16]** Networks, systems and applications are monitored for anomalous behaviour and potential incidents are evaluated. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Security-relevant events (incl. administrator/user activities) are logged centrally via {{TECH_SIEM}} according to determined and assessed requirements and evaluated regularly for violations (BL-OPS-04); for external services, the monitoring options are taken into account. Logs are protected against tampering, retention {{LOG_RETENTION}}, and an escalation procedure is established (see {{LINK:VA-13}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, additional (e.g. contractual) logging requirements are implemented and remote access sessions are logged. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, every access to corresponding data is logged, as far as technically/legally permissible.{{/if}} +{{/if}} + +### 3.5 Handling of vulnerabilities + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.5{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.8{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Information about technical vulnerabilities of the IT systems used is collected (e.g. manufacturer information, system audits, CVE database). + +- **[MUST]** Potentially affected IT systems and software are identified and the risk caused by the vulnerability is assessed. + +- **[MUST]** Risks arising from vulnerabilities are treated. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Appropriate patch management is defined and implemented (e.g. patch testing and installation). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Risk-mitigating measures are implemented where necessary. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The successful installation of patches is verified in a suitable manner. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.8]** Information on technical vulnerabilities is obtained, exposure is evaluated and appropriate measures are taken. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Vulnerability information is collected (manufacturer information, CVE, scans BL-OPS-02), affected systems are identified, the risk is assessed and treated on a risk basis according to BL-OPS-01 via patch/change management (see {{LINK:VA-06}}) (critical {{PATCH_SLA_CRIT}}); the successful installation is verified and tracked in {{TOOL_TICKET}}, and risk-mitigating measures apply where necessary. + +### 3.6 Technical review of IT systems + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.6{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.34{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Requirements for the review (audit) of IT systems or services are determined. + +- **[MUST]** The scope of the system review is defined in good time. + +- **[MUST]** System or service reviews are coordinated with the operators and users of the IT systems/services. + +- **[MUST]** The results of system/service reviews are stored in a traceable manner and reported to the responsible management. + +- **[MUST]** Measures are derived from the results and implemented within an appropriate period. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** System and service reviews are planned taking possible security risks (e.g. disruptions) into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Regular system or service reviews are carried out; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Within an appropriate period after completion of the review, a report is prepared. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** For critical IT systems/services, additional review requirements have been identified and are met (e.g. service-specific tests/tools and/or manual penetration tests, risk-based intervals). (A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** IT systems and services are scanned regularly for vulnerabilities. For systems/services that cannot be scanned, suitable protective measures are to be implemented. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.34]** Audit tests and similar activities on operational systems are planned and agreed to avoid disruption. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Requirements and scope of technical reviews are determined and coordinated with operators/users; systems are configured according to hardening requirements (BL-OPS-07, e.g. CIS benchmarks) and reviewed on a risk basis (see {{LINK:VA-06}}). Results are stored in a traceable manner, reported to management, and measures are implemented on time. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, additional reviews (penetration tests {{PENTEST_FREQ}}, BL-OPS-08) are carried out for critical systems. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, systems are scanned regularly for vulnerabilities, or systems that cannot be scanned are protected by suitable measures.{{/if}} +{{/if}} + +### 3.7 Network security + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.7{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.20, A.8.22{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Requirements for the management and control of networks are determined and met. + +- **[MUST]** Requirements for network segmentation are determined and met. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Procedures for the management and control of networks are defined. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** For a risk-based network segmentation, the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Extended requirements for the management and control of networks are determined and implemented. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.20]** Networks and network devices are secured, managed and controlled to protect information. + +- **[ISO A.8.22]** Groups of information services, users and systems are segregated in networks. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The network is segmented on a risk basis according to the protection need (BL-NET-01), access-controlled and secured externally via a firewall (default deny, BL-NET-02); management/control procedures and an up-to-date network plan/segmentation concept are maintained in the network/network services register ({{LINK:REG-NET}}).{{#if FLAG_OT_USED}} Production/OT networks are separated from office networks and specially secured.{{/if}} + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, extended requirements for network management and control are determined and implemented. +{{/if}} + +### 3.8 Data backup and recovery + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.9{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.13{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Backup concepts exist for relevant IT systems. Appropriate protective measures for the confidentiality, integrity and availability of the backups are taken into account. + +- **[MUST]** Recovery concepts exist for relevant IT services. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** For each relevant IT service, a backup and recovery concept exists. Dependencies between IT services and the recovery sequence are taken into account. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Backup and recovery concepts are reviewed methodically at regular intervals. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The fundamental recoverability is taken into account and tested (e.g. sample tests, test systems). (I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** (Additional) backups are carried out via offline procedures, immutable backups or an isolated IAM solution. (I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Recovery procedures are tested technically and methodically at regular intervals. (I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Geographical redundancy is taken into account in backup and recovery concepts. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.13]** Backup copies of information, software and systems are created in accordance with the backup concept and tested regularly. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Backup and recovery concepts for relevant IT services exist (protection of confidentiality/integrity/availability, dependencies and sequence taken into account); backups are performed according to the scheme {{BACKUP_SCHEME}} via {{TECH_BACKUP}} (BL-OPS-05), retention {{BACKUP_RETENTION}}, recovery regulated and tested (see {{LINK:VA-05}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, concepts are reviewed methodically and recoverability is tested. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, additional offline/immutable backups, methodical technical restore tests and geographical redundancy are carried out.{{/if}} +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_IT_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Secure IT operations | +| {{ROLE_ISB}} | Monitoring | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_IT_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-04}}, {{LINK:VA-05}}, {{LINK:VA-06}}, {{LINK:VA-13}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R04}}, {{LINK:R08}}, {{LINK:R11}} + + + +{{#if FLAG_FW_ISO27001}} + +### 3.9 Threat intelligence + +*Requirement reference:* ISO/IEC 27001 A.5.7 + +**Requirement** + + +- **[ISO A.5.7]** Information on threats is collected and analysed to produce and use threat intelligence. + +**Implementation at {{ORG_NAME}}** + + +Information on threats is obtained regularly from named sources ({{THREAT_INTEL_SOURCES}}) and evaluated by {{ROLE_IT_LEAD}} for relevance to the organisation's own systems and services. Relevant findings lead to actions in vulnerability and patch management ({{LINK:VA-06}}), to adjustments of monitoring ({{LINK:VA-13}}) or to a new risk assessment. Evaluation and resulting actions are documented in {{TOOL_TICKET}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.10 Documented operating procedures + +*Requirement reference:* ISO/IEC 27001 A.5.37 + +**Requirement** + + +- **[ISO A.5.37]** Operating procedures for information processing facilities are documented and made available to the personnel concerned. + +**Implementation at {{ORG_NAME}}** + + +Operating procedures for information processing facilities are documented and accessible to the personnel who carry them out. They cover commissioning and configuration, operation and monitoring, backup, handling of faults, maintenance and decommissioning. The documentation is updated through change management (BL-OPS-09) whenever changes occur and is checked for currency at least {{POLICY_REVIEW_CYCLE}}. Responsible: {{ROLE_IT_LEAD}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.11 Capacity management + +*Requirement reference:* ISO/IEC 27001 A.8.6 + +**Requirement** + + +- **[ISO A.8.6]** Resources are monitored and capacity is adjusted to current and expected demand. + +**Implementation at {{ORG_NAME}}** + + +The utilisation of the relevant resources — compute, memory, storage, network bandwidth, licences and staffing in IT operations — is monitored {{CAPACITY_REVIEW_FREQ}} (BL-OPS-11). Exceeded thresholds raise an alert; future demand is taken into account in projects and significant changes. Capacity constraints that affect the availability requirements are recorded and treated as a risk. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.12 Data leakage prevention + +*Requirement reference:* ISO/IEC 27001 A.8.12 + +**Requirement** + + +- **[ISO A.8.12]** Measures to prevent data leakage are applied to systems, networks and devices that process sensitive information. + +**Implementation at {{ORG_NAME}}** + + +For systems, networks and devices that process protected information, measures against unauthorised outflow are in place (BL-OPS-12); at least {{DLP_SCOPE}} are covered. The measures follow the classification ({{LINK:R02}}): rules for disclosure, control of transfer channels, restriction of removable media (BL-EP-03) as well as logging and analysis of conspicuous transfers (BL-OPS-04). Detected violations are handled as security events ({{LINK:VA-01}}); where analysis relates to individuals, co-determination rights are observed. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.13 Clock synchronisation + +*Requirement reference:* ISO/IEC 27001 A.8.17 + +**Requirement** + + +- **[ISO A.8.17]** System clocks are synchronised to approved time sources. + +**Implementation at {{ORG_NAME}}** + + +The system clocks of all logging systems are synchronised to {{NTP_SOURCES}} (BL-OPS-10). Deviations are monitored and reported. A uniform time base and time zone is a prerequisite for the analysis of logs ({{LINK:VA-13}}) and for preserving evidence in the event of an incident. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md new file mode 100644 index 0000000..d3cbdd4 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md @@ -0,0 +1,219 @@ +# Policy Secure System Procurement and Development + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs information security in procurement and development, requirements for network services as well as return and secure deletion. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Security in procurement and development + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.4, A.8.25, A.8.26, A.8.27, A.8.28, A.8.29, A.8.30, A.8.33{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The information security requirements associated with the design and development of an IT service are determined and taken into account. + +- **[MUST]** The information security requirements associated with the procurement or extension of IT services and components are determined and taken into account. + +- **[MUST]** Information security requirements in connection with changes to developed IT services are taken into account. + +- **[MUST]** System acceptance tests are carried out taking the information security requirements into account. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Requirement specifications are created; the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Requirement specifications are checked against the information security requirements. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The IT service is checked for compliance with the specifications before production use. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The use of production data for test purposes is avoided as far as possible (anonymisation/pseudonymisation where applicable); the relevant aspects are taken into account. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Test systems receive protective measures comparable to the production environment when production data is used for testing. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** The security of purpose-built or substantially adapted software is tested upon commissioning, upon substantial changes or regularly (e.g. penetration test). (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.4]** Read and write access to source code, development tools and software libraries is appropriately managed. + +- **[ISO A.8.25]** Rules for a secure development life cycle of software and systems are established and applied. + +- **[ISO A.8.26]** Information security requirements are identified, specified and taken into account when developing or acquiring applications. + +- **[ISO A.8.27]** Principles for engineering secure systems are established, documented and applied. + +- **[ISO A.8.28]** Secure coding principles are applied to software development. + +- **[ISO A.8.29]** Security testing is integrated into the development and acceptance process. + +- **[ISO A.8.30]** Outsourced system development is directed, monitored and reviewed. + +- **[ISO A.8.33]** Test information is selected, protected and managed with care. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Information security requirements are an integral part of the design, procurement, extension and modification of IT services (security by design); requirement specification, review and acceptance tests under security aspects are carried out following the procedure Secure Procurement/Development & Acceptance ({{LINK:VA-16}}); production deployment only after review in {{TOOL_TICKET}}. Production data in tests is avoided/anonymised, and test systems are appropriately protected.{{#if FLAG_DEV_INHOUSE}} For in-house development, secure coding requirements apply with code reviews and automated security tests (SAST/dependency scan) in accordance with {{LINK:VA-16}}.{{/if}} + +{{#if FLAG_ELEVATED_PROTECTION}} + +{{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, the security of purpose-built or substantially adapted software is tested upon commissioning, upon substantial changes or regularly (penetration test).{{/if}} +{{/if}} + +### 3.2 Requirements for network services + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.21{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Requirements for the information security of network services are determined and met. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A procedure for securing and using network services is defined and implemented. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The requirements are agreed in the form of SLAs. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Appropriate redundancy solutions are implemented. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** Procedures for monitoring the quality of network traffic (e.g. traffic flow analyses, availability measurements) are defined and carried out. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.21]** Security mechanisms, service levels and requirements for network services are identified, implemented and monitored. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +For the network services used (internal/external), security requirements are determined, agreed in SLAs and implemented via a procedure; appropriate redundancies are in place. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, procedures for monitoring network traffic quality (traffic flow analyses, availability measurements) are defined and carried out. +{{/if}} + +### 3.3 Return and secure deletion + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.11, A.7.14, A.8.10{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A description of the termination process is in place, adapted to changes and regulated contractually. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.11]** Personnel and external users return all assets in their possession upon termination of employment or contract. + +- **[ISO A.7.14]** Equipment containing storage media is securely sanitised before disposal or re-use. + +- **[ISO A.8.10]** Information stored in systems and on media is deleted when no longer required. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Return and secure deletion/destruction of information and assets (upon end of contract, device decommissioning) are regulated according to BL-DEL-01, agreed contractually, adapted to changes and evidenced (deletion log). + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_IT_LEAD}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Procurement/development | +| {{ROLE_ISB}} | Security requirements | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_IT_LEAD}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R02}}, {{LINK:R10}}, {{LINK:R12}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md new file mode 100644 index 0000000..9382f20 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md @@ -0,0 +1,117 @@ +# Policy Cloud, AI and External IT Services + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs protection in outsourced/shared external IT services (cloud) as well as the use of AI/GenAI services. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Protection in shared external IT services + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.23{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** An effective separation (e.g. tenant separation) prevents unauthorised users of other organisations from accessing one's own information. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The provider's separation concept is documented and adapted to changes; the relevant aspects are taken into account. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.23]** Processes for acquisition, use, management and exit of cloud services are established in line with the information security requirements. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +For shared external IT services, effective tenant separation is required and contractually assured; the provider's separation concept is documented and updated upon changes.{{#if FLAG_CLOUD_USED}} Cloud services are assessed before use (protection need, data location/EU, encryption, exit) and approved by {{ROLE_ISB}}; the approvals are maintained in the register of external IT/cloud/AI services ({{LINK:REG-EXT-SERVICES}}) (see {{LINK:VA-11}}).{{/if}} + +{{#if FLAG_AI_USED}} +### 3.2 Use of AI/GenAI services (supplement R12, not ISA) + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The use of AI/GenAI services is regulated; only approved services are used. + +- **[MUST]** The input of confidential or personal information into non-approved AI services is prohibited; the permissible data classes per service are defined. + +- **[MUST]** For approved AI services, it is clarified and contractually ensured that inputs are not used for training or passed on. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Results of AI services are reviewed before business-critical use (human in the loop); the use of AI is documented and regulatory requirements (e.g. EU AI Act) are taken into account. +{{/if}} +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The use of AI/GenAI services is regulated; only services approved by {{ROLE_ISB}} (maintained in the register of external IT/cloud/AI services {{LINK:REG-EXT-SERVICES}}) may be used (see {{LINK:VA-11}}). The permissible data classes per service are defined, and the input of confidential/personal data into non-approved services is prohibited; upon approval, it is contractually ensured that inputs are not used for training or passed on. AI results are reviewed before critical use (human in the loop), the use is documented and the EU AI Act is taken into account. + +{{/if}} +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Approval/steering | +| {{ROLE_IT_LEAD}} | Technical safeguarding | +| Business units | Use of approved services | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-11}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R09}}, {{LINK:R11}}, {{LINK:R13}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md new file mode 100644 index 0000000..20847cf --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md @@ -0,0 +1,250 @@ +# Policy Supplier and Service Provider Management + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs ensuring information security at suppliers, confidentiality agreements and the delineation of responsibilities. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Information security at suppliers + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 6.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.19, A.5.22{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Contractors and partners are subjected to a security risk assessment. + +- **[MUST]** An appropriate level of information security is ensured through contractual agreements with contractors and partners. + +- **[MUST]** Where applicable, contractual agreements with clients/customers are passed on to contractors and partners. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Contractors and partners are contractually obliged to pass on requirements for an appropriate level of information security to their subcontractors. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Performance reports and documents from contractors and partners are reviewed. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** It is demonstrated that the supplier's level of information security is appropriate to the protection need (e.g. reviewed questionnaire/self-disclosure, attestation, certificate, supplier audit). (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The degree of fulfilment of the required evidence by the supplier is documented, reviewed and monitored regularly and upon changes. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The supplier's compliance with contractual agreements is checked, documented, reviewed and monitored regularly and upon changes. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** The appropriate level of information security should be demonstrated by a third-party audit (an appropriate TISAX label or similar) or an appropriate supplier audit. Without an audit, management must make a risk-based decision to continue; evidence of this decision exists. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[VERY HIGH]** Contractual obligations towards customers regarding transparency of supply chain risks are fulfilled. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.19]** Processes to manage the information security risks arising from supplier relationships are defined and implemented. + +- **[ISO A.5.22]** The information security of supplier services is monitored and reviewed regularly, and changes are managed. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Contractors/partners are subjected to a security risk assessment (BL-SUP-01) and contractually obliged to an appropriate level of information security (incl. passing on to subcontractors and customer requirements); the supplier register is maintained in the ISMS tool ({{TOOL_NAME}}), and performance reports are reviewed (see {{LINK:VA-10}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, the supplier's level of security is demonstrated (self-disclosure/attestation/certificate/audit) and compliance is documented and monitored regularly and upon changes. {{#if FLAG_VERY_HIGH_PROTECTION}}Where the protection need is very high, the evidence is provided via a third-party audit (TISAX or similar) or a documented risk-based management decision; transparency obligations regarding supply chain risks are fulfilled.{{/if}} +{{/if}} + +### 3.2 Confidentiality agreements + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 6.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.20{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The confidentiality requirements are determined and met. + +- **[MUST]** Requirements and procedures for applying confidentiality agreements are known to all persons who pass on information requiring protection. + +- **[MUST]** Valid confidentiality agreements are concluded before information requiring protection is passed on. + +- **[MUST]** The requirements and procedures for using confidentiality agreements and for handling information requiring protection are reviewed regularly. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Templates for confidentiality agreements are available and checked for legal applicability. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Confidentiality agreements cover the persons/organisations involved, the type of information, the subject matter, the period of validity and the responsibilities of the obligated party. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Confidentiality agreements contain provisions for handling information requiring protection beyond the contractual relationship. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** Ways to demonstrate compliance (e.g. review by independent third parties or audit rights) are defined. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** A process for monitoring the period of validity of temporary confidentiality agreements and for timely renewal is defined and implemented. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.20]** Relevant information security requirements are agreed with each supplier and recorded contractually. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Confidentiality requirements are determined and known; before information requiring protection is passed on, valid NDAs based on reviewed standard templates (process see {{LINK:VA-10}}) (with parties, type of information, subject matter, validity, responsibilities and post-contractual provisions) are concluded and stored in the ISMS tool. Requirements/procedures and periods of validity are monitored regularly, and ways to demonstrate compliance are defined. + +### 3.3 Delineation of responsibilities + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 6.1.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.21{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** The IT services concerned are identified. + +- **[MUST]** The security requirements relevant to the IT service are determined. + +- **[MUST]** The organisation responsible for implementing the requirement is defined and aware of its responsibility. + +- **[MUST]** Mechanisms for shared responsibilities are specified and implemented. + +- **[MUST]** The responsible organisation fulfils its respective responsibilities. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** For IT services, the configuration is designed, implemented and documented on the basis of the necessary security requirements. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The responsible personnel is appropriately trained. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** A list of the IT services concerned and the respective responsible IT service providers exists. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The applicability of the ISA controls has been assessed and documented. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The service configuration is included in the regular security assessments. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** It is demonstrated that the IT service providers fulfil their responsibility. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HIGH]** The integration into local protective measures (e.g. secure authentication mechanisms) is established and documented. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.21]** Processes to manage information security risks in the ICT product and service supply chain are defined and implemented. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +The IT services concerned and their security requirements are identified; responsibilities between the organisation and external IT service providers (incl. mechanisms for shared responsibility) are defined, known and fulfilled (see {{LINK:VA-10}}); the IT services and service providers concerned are maintained in the register of external IT/cloud/AI services ({{LINK:REG-EXT-SERVICES}}). The configuration is implemented on a requirements basis and documented, and the personnel is trained. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Where the protection need is high, a list of the IT services and responsible service providers exists, the applicability of the ISA controls is assessed/documented, the service configuration is part of regular security assessments, the fulfilment of responsibility is demonstrated, and the integration into local protective measures is documented. +{{/if}} + +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Supplier management | +| Procurement | Contractual integration | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Associated procedures: {{LINK:VA-10}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:R01}}, {{LINK:R12}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/richtlinien/R14_Compliance-und-Datenschutz.md b/seed/isms-vorlagenpaket-v2-en/richtlinien/R14_Compliance-und-Datenschutz.md new file mode 100644 index 0000000..1217db7 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/richtlinien/R14_Compliance-und-Datenschutz.md @@ -0,0 +1,129 @@ +# Policy Compliance and Data Protection + +| Document information | Value | +|-----------------------|------| +| Document type | Policy | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Responsible | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Purpose + +This policy governs compliance with regulatory/contractual requirements as well as the protection of personal data. It elaborates the information security policy ({{LINK:L00}}) and serves to meet the requirements of VDA ISA 2027. + +## 2. Scope + +This policy applies within the defined ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Requirements and implementation + +> Structure per section: **Requirement** (1:1 from VDA ISA; [MUST]/[SHOULD] and — where the protection need applies — [HIGH]/[VERY HIGH]) and **Implementation at {{ORG_NAME}}** (consolidated, to be adjusted where necessary). + +### 3.1 Regulatory and contractual compliance + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 7.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.31, A.5.32, A.5.33{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Legal, regulatory and contractual requirements relevant to information security are determined regularly. + +- **[MUST]** Policies for complying with the requirements are defined, implemented and communicated to the responsible persons. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SHOULD]** The integrity of records in accordance with legal, regulatory and contractual requirements as well as business requirements is taken into account. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.31]** Legal, statutory, regulatory and contractual information security requirements are identified, documented and kept up to date. + +- **[ISO A.5.32]** Appropriate procedures to protect intellectual property rights are implemented. + +- **[ISO A.5.33]** Records are protected against loss, destruction, falsification, unauthorised access and unauthorised release. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Relevant legal, regulatory and contractual requirements are determined regularly and recorded in a compliance/legal register in the ISMS tool ({{TOOL_NAME}}); policies for compliance are defined, implemented and communicated to the responsible persons, and the integrity of records is taken into account. + +{{#if FLAG_PERSONAL_DATA}} +### 3.2 Protection of personal data + + +*Requirement reference:* {{#if FLAG_FW_TISAX}}VDA ISA 7.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.34{{/if}} + + +**Requirement** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Requirements per VDA ISA 2027:*{{/if}} + + +- **[MUST]** Legal and contractual information security requirements for procedures and processes when processing personal data are determined. + +- **[MUST]** Provisions for complying with legal and contractual requirements for the protection of personal data are defined and known to the persons involved. + +- **[MUST]** Processes and procedures for protecting personal data are taken into account in the information security management system. +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Requirements per ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.34]** Requirements for the protection of personally identifiable information are identified and met in accordance with applicable obligations. +{{/if}} + + +**Implementation at {{ORG_NAME}}** + + +Legal and contractual requirements for the processing of personal data (GDPR) are determined; provisions are defined, known to those involved and taken into account in the ISMS. {{ROLE_DPO}} is involved, the record of processing activities is maintained in the ISMS tool ({{TOOL_NAME}}), and TOMs and deletion concepts (BL-DEL-01) are regulated; legal register review, deletion periods and data subject rights are processed following the data protection/compliance maintenance procedure ({{LINK:VA-18}}). + +{{/if}} +## 4. Binding nature + +This policy is binding for all affected roles within the scope. Compliance is monitored by {{ROLE_ISB}}. + +## 5. Roles and responsibilities + +| Role | Responsibility in this policy | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Compliance register | +| {{ROLE_DPO}} | Data protection | + +## 6. Review and update + +This policy is reviewed at least {{REVIEW_CYCLE}} and on an ad-hoc basis by {{ROLE_ISB}} and approved by {{ROLE_MANAGEMENT}}. + +## 7. Evidence + +The evidence is not maintained in this document but centrally in the evidence register ({{LINK:NACHWEISREGISTER}}) and in the associated entries of the ISMS tool ({{TOOL_NAME}}). + +## 8. Related documents + +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} +- Evidence register: {{LINK:NACHWEISREGISTER}} +- Further: {{LINK:L00}}, {{LINK:R03}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/variables.schema.json b/seed/isms-vorlagenpaket-v2-en/variables.schema.json new file mode 100644 index 0000000..c3f065f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/variables.schema.json @@ -0,0 +1,379 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ISMS Template Package v2 – Wizard Variables (VDA ISA 2027 / Information Security)", + "description": "Single source of truth for all wizard variables. Convention: UPPER_SNAKE_CASE, placeholder {{NAME}}. Feature flags control {{#if FLAG_X}} blocks. The developer generates the wizard inputs from this schema.", + "version": "2.0", + "type": "object", + "properties": { + "ORG_NAME": { + "type": "string", + "title": "Organisation (full name)", + "example": "Example Ltd" + }, + "ORG_SHORT": { + "type": "string", + "title": "Organisation (short name)", + "example": "Example" + }, + "ISMS_SCOPE": { + "type": "string", + "title": "Scope (short label)", + "example": "IT & Development, North Plant" + }, + "ISMS_SCOPE_DESCRIPTION": { + "type": "string", + "title": "Scope (description)" + }, + "ROLE_MANAGEMENT": { + "type": "string", + "title": "Top management", + "default": "Management" + }, + "ROLE_ISB": { + "type": "string", + "title": "Information Security Officer / CISO", + "default": "Information Security Officer (ISO)" + }, + "ROLE_IT_LEAD": { + "type": "string", + "title": "IT management", + "default": "IT management" + }, + "ROLE_HR_LEAD": { + "type": "string", + "title": "HR management", + "default": "HR management" + }, + "ROLE_DPO": { + "type": "string", + "title": "Data Protection Officer", + "default": "Data Protection Officer (DPO)" + }, + "DOC_VERSION": { + "type": "string", + "title": "Version", + "default": "1.0" + }, + "DOC_DATE": { + "type": "string", + "title": "Date", + "format": "date" + }, + "DOC_STATUS": { + "type": "string", + "title": "Status", + "enum": [ + "Draft", + "In review", + "Approved" + ], + "default": "Draft" + }, + "TOOL_NAME": { + "type": "string", + "title": "Name of the ISMS tool", + "default": "ISMS tool" + }, + "REVIEW_CYCLE": { + "type": "string", + "title": "Review cycle (free text)", + "default": "annually" + }, + "TECH_MFA": { + "type": "string", + "title": "MFA solution", + "default": "the MFA solution in use" + }, + "TECH_MALWARE": { + "type": "string", + "title": "Malware protection solution", + "default": "the endpoint protection solution in use" + }, + "TECH_BACKUP": { + "type": "string", + "title": "Backup solution", + "default": "the backup solution in use" + }, + "TECH_SIEM": { + "type": "string", + "title": "Logging/SIEM solution", + "default": "the central logging" + }, + "TECH_MDM": { + "type": "string", + "title": "MDM solution", + "default": "the MDM in use" + }, + "TECH_VPN": { + "type": "string", + "title": "VPN/remote access solution", + "default": "VPN" + }, + "TECH_CRYPTO": { + "type": "string", + "title": "Cryptography requirement/standard", + "default": "current BSI/industry recommendations" + }, + "TOOL_TICKET": { + "type": "string", + "title": "Ticket/workflow system (documentation location)", + "default": "ticketing system" + }, + "TOOL_IAM": { + "type": "string", + "title": "Directory/IAM system", + "default": "Entra ID / Active Directory" + }, + "PW_MIN_LENGTH": { + "type": "string", + "title": "Minimum password length (BL-IAM-01)", + "default": "12" + }, + "PW_COMPLEXITY": { + "type": "string", + "title": "Password complexity (BL-IAM-01)", + "default": "complexity of at least 3 of 4 character categories" + }, + "PW_ROTATION": { + "type": "string", + "title": "Password rotation (BL-IAM-01)", + "default": "no fixed forced rotation, change on an ad-hoc basis upon suspicion" + }, + "MFA_SCOPE": { + "type": "string", + "title": "MFA scope (BL-IAM-02)", + "default": "all remote access, administrative access and cloud services" + }, + "SESSION_TIMEOUT": { + "type": "string", + "title": "Session timeout (BL-IAM-03)", + "default": "15 min inactivity (privileged), 8 hours (standard)" + }, + "ACCOUNT_LOCKOUT": { + "type": "string", + "title": "Account lockout (BL-IAM-04)", + "default": "temporary lock after 10 failed attempts" + }, + "RECERT_FREQ": { + "type": "string", + "title": "Recertification (BL-IAM-05)", + "default": "semi-annually" + }, + "TLS_MIN": { + "type": "string", + "title": "Minimum TLS (BL-CRY-01)", + "default": "TLS 1.2 (recommendation TLS 1.3)" + }, + "CRYPTO_ALGO": { + "type": "string", + "title": "Permissible algorithms (BL-CRY-02)", + "default": "AES-256, RSA ≥ 3072 / ECC ≥ 256, SHA-256 or stronger" + }, + "PATCH_SLA_CRIT": { + "type": "string", + "title": "Patch SLA critical (BL-OPS-01)", + "default": "within 72 hours" + }, + "PATCH_SLA_HIGH": { + "type": "string", + "title": "Patch SLA high (BL-OPS-01)", + "default": "within 14 days" + }, + "PATCH_SLA_STD": { + "type": "string", + "title": "Patch SLA standard (BL-OPS-01)", + "default": "in the regular monthly patch cycle" + }, + "VULN_SCAN_FREQ": { + "type": "string", + "title": "Vulnerability scan (BL-OPS-02)", + "default": "monthly" + }, + "MALWARE_UPDATE": { + "type": "string", + "title": "Malware update (BL-OPS-03)", + "default": "automatically several times a day" + }, + "LOG_RETENTION": { + "type": "string", + "title": "Log retention (BL-OPS-04)", + "default": "90 days, up to 12 months depending on risk" + }, + "BACKUP_SCHEME": { + "type": "string", + "title": "Backup scheme (BL-OPS-05)", + "default": "3-2-1 (3 copies, 2 media, 1 offline/offsite)" + }, + "BACKUP_RETENTION": { + "type": "string", + "title": "Backup retention (BL-OPS-05)", + "default": "daily 30 days, monthly 12 months" + }, + "BACKUP_TEST_FREQ": { + "type": "string", + "title": "Recovery test (BL-OPS-06)", + "default": "annually" + }, + "PENTEST_FREQ": { + "type": "string", + "title": "Penetration test (BL-OPS-08)", + "default": "annually" + }, + "FLAG_INCLUDE_SHOULD": { + "type": "boolean", + "title": "Include SHOULD requirements (maturity level 3 = true)", + "default": true + }, + "FLAG_HIGH_PROTECTION": { + "type": "boolean", + "title": "Include additional requirements for HIGH protection need", + "default": false + }, + "FLAG_VERY_HIGH_PROTECTION": { + "type": "boolean", + "title": "Include additional requirements for VERY HIGH protection need", + "default": false + }, + "FLAG_ELEVATED_PROTECTION": { + "type": "boolean", + "title": "Derived: HIGH OR VERY_HIGH active (set by the wizard = FLAG_HIGH_PROTECTION || FLAG_VERY_HIGH_PROTECTION)", + "default": false + }, + "FLAG_CLOUD_USED": { + "type": "boolean", + "title": "Cloud services in use", + "default": true + }, + "FLAG_AI_USED": { + "type": "boolean", + "title": "AI/GenAI services in use", + "default": true + }, + "FLAG_OT_USED": { + "type": "boolean", + "title": "Production/OT environment present", + "default": false + }, + "FLAG_DEV_INHOUSE": { + "type": "boolean", + "title": "In-house software development", + "default": false + }, + "FLAG_MOBILE_WORK": { + "type": "boolean", + "title": "Mobile working / home office permitted", + "default": true + }, + "FLAG_MOBILE_DEVICES": { + "type": "boolean", + "title": "Mobile devices / data media in use", + "default": true + }, + "FLAG_CRYPTO_PKI": { + "type": "boolean", + "title": "Own PKI / certificate management", + "default": false + }, + "FLAG_EXTERNAL_IT": { + "type": "boolean", + "title": "External IT service providers used", + "default": true + }, + "FLAG_PERSONAL_DATA": { + "type": "boolean", + "title": "Processing of personal data", + "default": true + }, + "FLAG_CUSTOMER_SYSTEMS": { + "type": "boolean", + "title": "Access to customer systems (e.g. OEM)", + "default": false + }, + "FLAG_PROTOTYPE_PROTECTION": { + "type": "boolean", + "title": "Assessment objective prototype protection active (chapter 8.x)", + "default": false + }, + "FLAG_ISB_INTERNAL": { + "type": "boolean", + "title": "ISO staffed internally", + "default": true + }, + "FLAG_ISB_EXTERNAL": { + "type": "boolean", + "title": "ISO staffed externally (external service provider)", + "default": false + }, + "FLAG_FW_TISAX": { + "type": "boolean", + "title": "Framework: apply TISAX / VDA ISA", + "default": true + }, + "FLAG_FW_ISO27001": { + "type": "boolean", + "title": "Framework: apply ISO/IEC 27001", + "default": false + }, + "POLICY_REVIEW_CYCLE": { + "type": "string", + "title": "Review cycle for the policy and thematic policies", + "example": "annually", + "default": "annually" + }, + "MGMT_REVIEW_CYCLE": { + "type": "string", + "title": "Management review interval", + "example": "annually", + "default": "annually" + }, + "RISK_REVIEW_CYCLE": { + "type": "string", + "title": "Risk assessment interval", + "example": "annually", + "default": "annually" + }, + "RECORDS_RETENTION": { + "type": "string", + "title": "Retention of superseded document versions", + "example": "3 years", + "default": "3 years" + }, + "AUTHORITY_CONTACTS": { + "type": "string", + "title": "Relevant authorities and reporting bodies", + "example": "data protection authority, police, national CERT", + "default": "data protection authority, police, national CERT" + }, + "THREAT_INTEL_SOURCES": { + "type": "string", + "title": "Sources of threat intelligence", + "example": "national CERT advisories, vendor bulletins, CVE feeds", + "default": "national CERT advisories, vendor bulletins, CVE feeds" + }, + "CAPACITY_REVIEW_FREQ": { + "type": "string", + "title": "Capacity monitoring interval", + "example": "monthly", + "default": "monthly" + }, + "NTP_SOURCES": { + "type": "string", + "title": "Approved time sources", + "example": "two independent, trusted NTP sources", + "default": "two independent, trusted NTP sources" + }, + "DLP_SCOPE": { + "type": "string", + "title": "Channels covered against data leakage", + "example": "e-mail, removable media, cloud storage", + "default": "e-mail, removable media, cloud storage" + } + }, + "required": [ + "ORG_NAME", + "ISMS_SCOPE", + "ISMS_SCOPE_DESCRIPTION", + "DOC_VERSION", + "DOC_DATE" + ] +} diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md new file mode 100644 index 0000000..031ed85 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md @@ -0,0 +1,71 @@ +# Incident Response and Reporting Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-01) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the reporting, assessment, handling and follow-up of information security incidents. It operationalises the associated policy ({{LINK:R04}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Reporting of a security event (employees, technology/monitoring, external parties) via the defined reporting path. + +## 4. Inputs + +- Report/alert with a brief description +- Affected systems/information (asset inventory) +- Classification/protection need + +## 5. Process + +1. Report the event: record the report via {{TOOL_TICKET}} or email to {{ROLE_ISB}}. +2. Triage & classification: determine relevance, severity and category. +3. Containment: initiate immediate measures to limit the damage. +4. Remediation & recovery: eliminate the cause, restore normal operations. +5. Check reporting obligations: customers/OEM, authorities, and for personal data {{ROLE_DPO}} (72-hour deadline). +6. Documentation & lessons learned: close the incident, derive improvement measures. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Report the event | Reporting person | {{ROLE_ISB}} | - | - | +| 2 | Triage & classification | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Containment | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | +| 4 | Remediation & recovery | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 5 | Check reporting obligations | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | {{ROLE_DPO}} | - | +| 6 | Documentation & lessons learned | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | {{ROLE_MANAGEMENT}} | + +## 7. Result & evidence + +Documented, closed incident in {{TOOL_TICKET}}; derived measures in the ISMS tool ({{TOOL_NAME}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Time to detect/acknowledge +- Time to resolve +- Share of reports made on time + +## 9. Related documents + +- Associated policy: {{LINK:R04}} +- {{LINK:VA-02}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md new file mode 100644 index 0000000..14926d4 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md @@ -0,0 +1,72 @@ +# IT Emergency and Recovery Procedure (BCM) + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-02) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the maintenance and recovery of critical IT services in the event of failure or crisis. It operationalises the associated policy ({{LINK:R04}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Failure of critical IT services, emergency or crisis (escalation from VA-01). + +## 4. Inputs + +- List of critical IT services with RTO/RPO +- Recovery plans +- Backup status (VA-05) + +## 5. Process + +1. Identify & classify the emergency: assess the extent, convene the crisis team if necessary. +2. Activate communication: inform internal/external stakeholders. +3. Prioritise recovery: order services according to RTO/RPO. +4. Perform recovery: restore systems/data from backup (VA-05). +5. Confirm & document the return to normal operations. +6. Follow-up & test update: update the plan, exercise {{BACKUP_TEST_FREQ}}. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Identify & classify the emergency | {{ROLE_IT_LEAD}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 2 | Activate communication | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | - | Employees | +| 3 | Prioritise recovery | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Perform recovery | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 5 | Confirm return to normal operations & | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | {{ROLE_MANAGEMENT}} | +| 6 | Follow-up & test update | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Recovered services; documented emergency/test in the ISMS tool ({{TOOL_NAME}}); updated recovery plans. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Adherence to RTO/RPO +- Success rate of recovery tests +- Up-to-dateness of the emergency plans + +## 9. Related documents + +- Associated policy: {{LINK:R04}} +- {{LINK:VA-01}} +- {{LINK:VA-05}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-03_Berechtigungsverfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-03_Berechtigungsverfahren.md new file mode 100644 index 0000000..8eb574a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-03_Berechtigungsverfahren.md @@ -0,0 +1,71 @@ +# Authorisation Procedure (Joiner/Mover/Leaver and Recertification) + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-03) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the request, approval, modification, revocation and regular review of access rights. It operationalises the associated policy ({{LINK:R08}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Joining, role change or leaving of a person; authorisation request; due recertification. + +## 4. Inputs + +- HR notification +- Role/rights catalogue (RBAC) +- Existing authorisations from the central directory ({{TOOL_IAM}}) + +## 5. Process + +1. Record the request: request access/right in {{TOOL_TICKET}} (joiner/mover). +2. Business approval: check the necessity according to the least-privilege principle and approve. +3. Implementation: set rights on a role basis in the central directory ({{TOOL_IAM}}). +4. Leaver/change: upon leaving/change, revoke/adjust rights without delay. +5. Recertification ({{RECERT_FREQ}}, BL-IAM-05): owners confirm/revoke rights. +6. Privileged accounts: review and log separately (BL-IAM-06). + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Record the request | Manager/business unit | {{ROLE_IT_LEAD}} | - | - | +| 2 | Business approval | Business unit/data owner | Business unit/data owner | {{ROLE_ISB}} | - | +| 3 | Implementation | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | Requester | +| 4 | Leaver/change | {{ROLE_IT_LEAD}} | {{ROLE_HR_LEAD}} | - | - | +| 5 | Recertification ({{RECERT_FREQ}}, BL-IAM-05) | Business unit/data owner | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 6 | Privileged accounts | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Documented requests/approvals in {{TOOL_TICKET}}; current authorisation status in the central directory ({{TOOL_IAM}}); recertification evidence. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of leaver rights revoked on time +- Recertification rate +- Number of orphaned/privileged accounts + +## 9. Related documents + +- Associated policy: {{LINK:R08}} +- {{LINK:VA-01}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md new file mode 100644 index 0000000..d164414 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md @@ -0,0 +1,71 @@ +# Change and Patch Management Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-04) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs planned changes to IT systems as well as the risk-oriented installation of patches. It operationalises the associated policy ({{LINK:R10}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Need for change, available patch or identified vulnerability (VA-06). + +## 4. Inputs + +- Change/patch request +- Risk assessment +- Patch SLA (BL-OPS-01) + +## 5. Process + +1. Request & classify the change (standard/normal/emergency) in {{TOOL_TICKET}}. +2. Risk/impact assessment incl. rollback plan. +3. Approval by CAB/responsible role. +4. Test in a separate environment (BL-OPS, R10). +5. Implementation in production in accordance with the patch SLA (critical {{PATCH_SLA_CRIT}}). +6. Verification & documentation of the result in {{TOOL_TICKET}}. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Request & classify the change | Requester | {{ROLE_IT_LEAD}} | - | - | +| 2 | Risk/impact assessment incl. rollback | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 3 | Approval by CAB/responsible role | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Test in a separate environment | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 5 | Implementation in production per patch SLA | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | Affected parties | +| 6 | Verification & documentation of the result | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Documented, approved and verified change/patch in {{TOOL_TICKET}}. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Patch compliance per criticality +- Share of successful changes (without rollback) +- Lead time of critical patches + +## 9. Related documents + +- Associated policy: {{LINK:R10}} +- {{LINK:VA-06}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-05_Backup-und-Restore-Verfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-05_Backup-und-Restore-Verfahren.md new file mode 100644 index 0000000..e88478f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-05_Backup-und-Restore-Verfahren.md @@ -0,0 +1,69 @@ +# Backup and Restore Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-05) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs data backup, retention and recovery according to the {{BACKUP_SCHEME}} scheme. It operationalises the associated policy ({{LINK:R10}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Regular backup run; recovery need; scheduled restore test. + +## 4. Inputs + +- Backup plan per system +- Classification/RPO +- Backup targets ({{TECH_BACKUP}}) + +## 5. Process + +1. Perform backup: automated backups in accordance with {{BACKUP_SCHEME}} (BL-OPS-05). +2. Monitoring: check success/failure, track failed runs ({{TOOL_TICKET}}). +3. Protection & offsite storage: 1 copy offline/immutable, retention {{BACKUP_RETENTION}}. +4. Process restore request (on demand/emergency, VA-02). +5. Perform & document recovery test ({{BACKUP_TEST_FREQ}}, BL-OPS-06). + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Perform backup | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Monitoring | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 3 | Protection & offsite storage | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 4 | Process restore request (on demand) | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | Requester | - | +| 5 | Recovery test ({{BACKUP_TEST_FREQ}}) | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Logged backups; documented restore tests; evidence in the ISMS tool ({{TOOL_NAME}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Backup success rate +- Success rate of restore tests +- Adherence to RPO + +## 9. Related documents + +- Associated policy: {{LINK:R10}} +- {{LINK:VA-02}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md new file mode 100644 index 0000000..a7cf736 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md @@ -0,0 +1,69 @@ +# Vulnerability Management Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-06) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the detection, assessment, treatment and technical review of vulnerabilities. It operationalises the associated policy ({{LINK:R10}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Regular scan ({{VULN_SCAN_FREQ}}), security advisory/CVE, penetration test ({{PENTEST_FREQ}}). + +## 4. Inputs + +- Scan/test reports +- Asset inventory & criticality +- Patch SLA (BL-OPS-01) + +## 5. Process + +1. Identification: evaluate vulnerability scan {{VULN_SCAN_FREQ}} (BL-OPS-02) and advisories. +2. Assessment & prioritisation according to criticality and exposure. +3. Initiate treatment: patch/change (VA-04) or compensating measure. +4. Technical review: hardening (BL-OPS-07) and penetration tests ({{PENTEST_FREQ}}, BL-OPS-08). +5. Tracking & verification of the remediation in {{TOOL_TICKET}}. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Identification | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Assessment & prioritisation by criticality | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 3 | Initiate treatment | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Technical review | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | External service provider | - | +| 5 | Tracking & verification of the remediation | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Tracked vulnerabilities with treatment status in {{TOOL_TICKET}}; test reports. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Mean time to remediate per criticality +- Open critical vulnerabilities +- Scan coverage + +## 9. Related documents + +- Associated policy: {{LINK:R10}} +- {{LINK:VA-04}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md new file mode 100644 index 0000000..95da9fe --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md @@ -0,0 +1,69 @@ +# Cryptography Concept and Key Management + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-07) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the use of cryptographic procedures and the management of keys throughout the lifecycle. It operationalises the associated policy ({{LINK:R09}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +New need for encryption/certificates; key renewal/revocation; change in the state of the art. + +## 4. Inputs + +- Permissible algorithms (BL-CRY-02) +- Protection need of the data +- Certificate/key inventory + +## 5. Process + +1. Determine need & procedure: select permissible algorithms {{CRYPTO_ALGO}} (BL-CRY-02). +2. Generate keys/certificates and distribute them securely (BL-CRY-05). +3. Storage & access protection (separate storage, {{#if FLAG_CRYPTO_PKI}}PKI, {{/if}}authorisations). +4. Ensure transmission protection: at least {{TLS_MIN}} (BL-CRY-01). +5. Document renewal/revocation/destruction. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Determine need & procedure | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 2 | Generate keys/certificates and distribute securely | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 3 | Storage & access protection (separate storage) | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 4 | Ensure transmission protection | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 5 | Document renewal/revocation/destruction | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Documented cryptography concept; traceable key/certificate lifecycle. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of compliant procedures/algorithms +- Expiring certificates without renewal +- Coverage of transport encryption + +## 9. Related documents + +- Associated policy: {{LINK:R09}} +- {{LINK:VA-04}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md new file mode 100644 index 0000000..05809ef --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md @@ -0,0 +1,69 @@ +# Asset and Classification Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-08) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the recording, owner assignment, classification and maintenance of information assets and assets. It operationalises the associated policy ({{LINK:R02}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +New/changed asset; procurement; regular inventory review. + +## 4. Inputs + +- Procurement/change notification +- Classification scheme +- Asset inventory ({{TOOL_NAME}}) + +## 5. Process + +1. Record the asset in the inventory ({{TOOL_NAME}}) with attributes. +2. Assign an owner. +3. Classify (confidentiality/integrity/availability) by the owner. +4. Apply handling requirements per protection class (labelling/storage/deletion BL-DEL-01). +5. Maintenance & review ({{REVIEW_CYCLE}}) for up-to-dateness. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Record the asset in the inventory ({{TOOL_NAME}}) | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Assign an owner | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | Asset owner | +| 3 | Classify (confidentiality/integrity) | Asset owner | Asset owner | {{ROLE_ISB}} | - | +| 4 | Apply handling requirements per protection class | Asset owner | {{ROLE_ISB}} | - | Employees | +| 5 | Maintenance & review ({{REVIEW_CYCLE}}) | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Up-to-date, classified asset inventory in the ISMS tool ({{TOOL_NAME}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Inventory coverage +- Share of classified assets +- Assets without an owner + +## 9. Related documents + +- Associated policy: {{LINK:R02}} +- {{LINK:VA-03}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-09_Risikomanagement-Verfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-09_Risikomanagement-Verfahren.md new file mode 100644 index 0000000..a727577 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-09_Risikomanagement-Verfahren.md @@ -0,0 +1,69 @@ +# Risk Management Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-09) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the identification, analysis, assessment, treatment and monitoring of information security risks. It operationalises the associated policy ({{LINK:R03}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +New system/project, incident, change, regular review cycle. + +## 4. Inputs + +- Asset/process list +- Assessment scales & acceptance thresholds +- Existing risk register + +## 5. Process + +1. Identify risks (assets, threats, vulnerabilities). +2. Analyse & assess (likelihood × impact) in the ISMS tool ({{TOOL_NAME}}). +3. Determine treatment (reduce/avoid/transfer/accept) and plan measures. +4. Document residual risk acceptance. +5. Monitor & update ({{REVIEW_CYCLE}} and on an ad-hoc basis). + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Identify risks (assets, threats) | {{ROLE_ISB}} | {{ROLE_ISB}} | Asset/process owners | - | +| 2 | Analyse & assess (likelihood × impact) | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Determine treatment (reduce/avoid) | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | Business unit | - | +| 4 | Document residual risk acceptance | {{ROLE_MANAGEMENT}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 5 | Monitor & update ({{REVIEW_CYCLE}}) | {{ROLE_ISB}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Maintained risk register with treatment plan and acceptance decisions in the ISMS tool ({{TOOL_NAME}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of treated risks +- Overdue measures +- Up-to-dateness of the risk register + +## 9. Related documents + +- Associated policy: {{LINK:R03}} +- {{LINK:VA-01}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md new file mode 100644 index 0000000..429176f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md @@ -0,0 +1,69 @@ +# Supplier Onboarding and Assessment Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-10) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the selection, security-related assessment, contractual commitment and monitoring of suppliers/service providers. It operationalises the associated policy ({{LINK:R13}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +New supplier/service provider with access to information; contract renewal; periodic review. + +## 4. Inputs + +- Service/protection-need description +- Risk classes (BL-SUP-01) +- NDA/contract templates + +## 5. Process + +1. Determine need & risk class (protection need, access). +2. Carry out security assessment (self-disclosure/evidence/TISAX). +3. Agree NDA & contractual security requirements. +4. Delineate responsibilities (operations/security/reporting). +5. Add to the supplier register ({{TOOL_NAME}}) and review {{REVIEW_CYCLE}}. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Determine need & risk class (protection need, access) | Procurement/business unit | {{ROLE_ISB}} | - | - | +| 2 | Security assessment (self-disclosure/evidence/TISAX) | {{ROLE_ISB}} | {{ROLE_ISB}} | Business unit | - | +| 3 | NDA & contractual security requirements | Procurement | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 4 | Delineate responsibilities (operations/security) | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 5 | Add to the supplier register ({{TOOL_NAME}}) | {{ROLE_ISB}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Assessed, contractually committed supplier in the supplier register ({{TOOL_NAME}}); NDA on file. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of assessed suppliers +- NDA coverage +- Overdue supplier reviews + +## 9. Related documents + +- Associated policy: {{LINK:R13}} +- {{LINK:VA-11}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md new file mode 100644 index 0000000..10406e5 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md @@ -0,0 +1,69 @@ +# Cloud and AI Approval Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-11) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the assessment and approval of cloud and AI/GenAI services as well as their permissible use. It operationalises the associated policy ({{LINK:R12}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Request to use a cloud or AI service. + +## 4. Inputs + +- Service description & provider information +- Protection need/data classes +- Contract/DPA documents + +## 5. Process + +1. Record the request in {{TOOL_TICKET}} (service, purpose, data classes). +2. Assessment: protection need, data location/EU, tenant separation, exit; for AI, exclusion of training/passing on. +3. Review contract/DPA (for AI: opt-out/enterprise contract, EU AI Act). +4. Approval & inclusion in the approval list ({{TOOL_NAME}}); define permissible data classes. +5. Use & control: human in the loop for AI, periodic review ({{REVIEW_CYCLE}}). + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Record the request in {{TOOL_TICKET}} (service) | Requester/business unit | {{ROLE_ISB}} | - | - | +| 2 | Assessment | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | {{ROLE_DPO}} | +| 3 | Review contract/DPA (for AI) | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | {{ROLE_DPO}} | - | +| 4 | Approval & inclusion in the approval list | {{ROLE_ISB}} | {{ROLE_ISB}} | - | Business unit | +| 5 | Use & control | Business unit | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Approval decision and approval list in the ISMS tool ({{TOOL_NAME}}); documented permissible data classes. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of approved vs. used services +- Shadow IT findings +- Overdue service reviews + +## 9. Related documents + +- Associated policy: {{LINK:R12}} +- {{LINK:VA-10}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-12_Awareness-und-Schulungsverfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-12_Awareness-und-Schulungsverfahren.md new file mode 100644 index 0000000..9af6b99 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-12_Awareness-und-Schulungsverfahren.md @@ -0,0 +1,69 @@ +# Awareness and Training Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-12) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the planning, delivery and evidence of awareness and training on information security. It operationalises the associated policy ({{LINK:R05}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Joining of new employees; annual training cycle; ad-hoc after incidents. + +## 4. Inputs + +- Training plan/curriculum (BL-HR-01) +- Target groups/roles +- Participation status ({{TOOL_NAME}}) + +## 5. Process + +1. Plan training needs & target groups (role-specific). +2. Deliver onboarding training upon joining. +3. Deliver regular training ({{REVIEW_CYCLE}}, BL-HR-01). +4. Check effectiveness (phishing simulation) and provide follow-up training. +5. Evidence participation in the ISMS tool ({{TOOL_NAME}}). + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Plan training needs & target groups (role-specific) | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_HR_LEAD}} | - | +| 2 | Deliver onboarding training upon joining | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | Employees | +| 3 | Regular training ({{REVIEW_CYCLE}}, BL-HR-01) | {{ROLE_ISB}} | {{ROLE_ISB}} | - | Employees | +| 4 | Check effectiveness (phishing simulation) | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 5 | Evidence participation in the ISMS tool ({{TOOL_NAME}}) | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Documented training participation and effectiveness measurement in the ISMS tool ({{TOOL_NAME}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Training completion rate +- Phishing click rate +- Share of role-specific training + +## 9. Related documents + +- Associated policy: {{LINK:R05}} +- {{LINK:VA-01}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md new file mode 100644 index 0000000..60e939f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md @@ -0,0 +1,69 @@ +# Logging and Monitoring Procedure + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-13) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the collection, protection, evaluation and retention of security-relevant log data. It operationalises the associated policy ({{LINK:R10}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Trigger + +Continuous operations; security-relevant event; alert from {{TECH_SIEM}}. + +## 4. Inputs + +- Log sources/systems +- Retention requirements (BL-OPS-04) +- Alerting rules + +## 5. Process + +1. Connect log sources and record centrally in {{TECH_SIEM}} (BL-OPS-04). +2. Ensure tamper protection & retention {{LOG_RETENTION}}. +3. Evaluation & alerting: maintain rules, check anomalies. +4. Hand over suspected cases to incident response (VA-01). +5. Regular review of coverage and rules. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Connect log sources and record centrally in {{TECH_SIEM}} | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Tamper protection & retention {{LOG_RETENTION}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 3 | Evaluation & alerting | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 4 | Hand over suspected cases to incident response (VA-01) | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 5 | Regular review of coverage and rules | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Central, protected logging with evaluation; evidence in the ISMS tool ({{TOOL_NAME}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Log source coverage +- Mean time to alert response +- Share of evaluable events + +## 9. Related documents + +- Associated policy: {{LINK:R10}} +- {{LINK:VA-01}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md new file mode 100644 index 0000000..45e2259 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md @@ -0,0 +1,71 @@ +# Personnel Security – Suitability Check & Sensitive Activities + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-14) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_HR_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the determination of sensitive activities, the suitability and identity check upon hiring as well as the handling of violations of information security and confidentiality obligations. It operationalises the associated policy ({{LINK:R05}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for all hiring, change and leaving processes. + +## 3. Trigger + +Hiring, change to a sensitive position, suspicion of a violation, regular review. + +## 4. Inputs + +- Register of sensitive activities ({{LINK:REG-SENS-ROLES}}) +- Job descriptions with security requirements +- HR notification; legal framework (data protection/co-determination) + +## 5. Process + +1. Determine sensitive activity areas/roles in the **register of sensitive activities ({{LINK:REG-SENS-ROLES}})** and define the required depth of checking per role. +2. Record requirements for positions in job descriptions and ensure their fulfilment. +3. Upon hiring, verify identity; check personal suitability within the legally permissible scope (job interview). +4. For sensitive roles, carry out extended checks (references, criminal record certificate) within the legally permissible scope. +5. Handle violations of information security/confidentiality obligations following a documented procedure; evidence in the personnel file. +6. Review sensitive roles and depth of checking regularly ({{REVIEW_CYCLE}}). + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Determine sensitive activities & depth of checking | {{ROLE_ISB}} | {{ROLE_HR_LEAD}} | Business unit | - | +| 2 | Requirements in job descriptions | {{ROLE_HR_LEAD}} | {{ROLE_HR_LEAD}} | Business unit | - | +| 3 | Verify identity / check suitability | {{ROLE_HR_LEAD}} | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Extended checks (sensitive roles) | {{ROLE_HR_LEAD}} | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | +| 5 | Handling of violations | {{ROLE_HR_LEAD}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 6 | Regular review | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_HR_LEAD}} | - | + +## 7. Result & evidence + +Maintained register of sensitive activities; documented suitability/verification evidence in the personnel file; documented violation cases. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of sensitive roles with documented depth of checking +- On-time identity/suitability checks +- Open violation cases + +## 9. Related documents + +- Associated policy: {{LINK:R05}} +- Register: {{LINK:REG-SENS-ROLES}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md new file mode 100644 index 0000000..8dd6b07 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md @@ -0,0 +1,72 @@ +# Internal Audits & Compliance Reviews + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-15) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the programme, planning, execution, reporting and measure tracking of internal audits as well as the independent review of the ISMS. It operationalises the associated policy ({{LINK:R03}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for all policies, procedures and technical requirements within the scope. + +## 3. Trigger + +Audit cycle (BL-GOV-01), material changes, request by management, prior findings. + +## 4. Inputs + +- Audit programme register ({{LINK:REG-AUDIT-PLAN}}) +- Controls / statement of applicability (SoA) +- Previous audit reports & open measures + +## 5. Process + +1. Plan the **audit programme** in the **register ({{LINK:REG-AUDIT-PLAN}})** (scope, controls reviewed, dates, auditors) — cycle per **BL-GOV-01**. +2. Conduct the audit **independently** (auditor ≠ person responsible for the area reviewed). +3. Record findings/deviations and create them as measures in the ISMS tool ({{TOOL_NAME}}). +4. Report the audit report to {{ROLE_MANAGEMENT}} (input for the management review). +5. Track measures through to completion. +6. Independent review/assessment at least per **BL-GOV-01** or after fundamental changes. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Plan the audit programme | {{ROLE_ISB}} | {{ROLE_ISB}} | Business units | - | +| 2 | Conduct the audit | Auditor (independent) | {{ROLE_ISB}} | Area reviewed | - | +| 3 | Record findings / create measures | {{ROLE_ISB}} | {{ROLE_ISB}} | Business unit | - | +| 4 | Report to management | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | - | {{ROLE_MANAGEMENT}} | +| 5 | Track measures | {{ROLE_ISB}} | {{ROLE_ISB}} | Business unit | - | +| 6 | Independent review | External/independent auditor | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | + +## 7. Result & evidence + +Audit reports, documented findings/measures and a maintained audit programme ({{LINK:REG-AUDIT-PLAN}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Audit coverage of the controls +- Open findings / on-time completion of measures +- Share of audits completed on time + +## 9. Related documents + +- Associated policy: {{LINK:R03}} +- Register: {{LINK:REG-AUDIT-PLAN}} +- Risk management procedure: {{LINK:VA-09}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md new file mode 100644 index 0000000..0f42709 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md @@ -0,0 +1,72 @@ +# Secure Procurement, Development & Acceptance + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-16) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure ensures that information security requirements are an integral part of the procurement, design, development, extension and modification of IT services and systems (security by design), including acceptance tests and test data handling. It operationalises the associated policy ({{LINK:R11}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for the procurement, in-house/external development and modification of IT services/systems. + +## 3. Trigger + +Procurement, new/further development or substantial modification of an IT service/system. + +## 4. Inputs + +- Security/protection-need requirements; applicable ISA controls +- Test/acceptance concept +- Where applicable, external services ({{LINK:REG-EXT-SERVICES}}) + +## 5. Process + +1. Specify security requirements (security by design) and take the protection need into account. +2. Carry out procurement/modification based on the security criteria.{{#if FLAG_EXTERNAL_IT}} External/cloud services are assessed via {{LINK:VA-11}} and maintained in the {{LINK:REG-EXT-SERVICES}}.{{/if}} +3. Acceptance tests under security aspects before production deployment; approval in {{TOOL_TICKET}} (change coupling {{LINK:VA-04}}). +4. Avoid or anonymise production data in tests; protect test systems appropriately. +5. {{#if FLAG_DEV_INHOUSE}} For in-house development, secure coding requirements apply with code reviews and automated security tests (SAST/dependency scan).{{/if}} +6. {{#if FLAG_VERY_HIGH_PROTECTION}} Where the protection need is very high, an additional independent security review/acceptance is carried out before approval.{{/if}} + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Specify security requirements | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | Business unit | - | +| 2 | Carry out procurement/modification | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 3 | Security acceptance / approval | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | Business unit | - | +| 4 | Test data handling | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_DPO}} | - | +| 5 | Secure coding / security tests | Development | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 6 | Additional review (very high protection need) | Independent auditor | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | + +## 7. Result & evidence + +Acceptance records, test reports and approvals (in {{TOOL_TICKET}}). Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of projects with a documented security acceptance +- Critical security findings before go-live +- Share of tests without real production data + +## 9. Related documents + +- Associated policy: {{LINK:R11}} +- Change procedure: {{LINK:VA-04}} +- Cloud/AI approval: {{LINK:VA-11}}; register: {{LINK:REG-EXT-SERVICES}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-17_Zutritts-und-Besuchermanagement.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-17_Zutritts-und-Besuchermanagement.md new file mode 100644 index 0000000..27fac3a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-17_Zutritts-und-Besuchermanagement.md @@ -0,0 +1,67 @@ +# Access & Visitor Management (physical) + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-17) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_IT_LEAD}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the granting and revocation of physical access rights, visitor management as well as the handling of utilities in security zones. It operationalises the associated policy ({{LINK:R07}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for all sites and security zones. + +## 3. Trigger + +Joining/leaving/role change, visit, change to the zone concept, regular review. + +## 4. Inputs + +- Zone/security concept ({{LINK:BASELINE}}, BL-PHY-01/02) +- Personnel/visitor notification +- Existing access authorisations + +## 5. Process + +1. Access rights to security zones are requested, approved and revoked via {{TOOL_TICKET}} (least-privilege principle). +2. Visitors are registered, identified and escorted in areas requiring protection. +3. Utilities, keys and badges are issued, taken back and documented. +4. Access authorisations are reviewed regularly ({{REVIEW_CYCLE}}) and adjusted without delay upon leaving/change. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Grant/revoke access rights | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 2 | Register/escort visitors | Reception/business unit | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 3 | Manage utilities/keys | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 4 | Review access authorisations | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | + +## 7. Result & evidence + +Up-to-date access authorisations and visitor logs. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Up-to-dateness of the access list +- Overdue recertifications of access rights +- Completeness of visitor logs + +## 9. Related documents + +- Associated policy: {{LINK:R07}} +- Authorisation procedure (logical analogue): {{LINK:VA-03}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md new file mode 100644 index 0000000..17a631d --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md @@ -0,0 +1,66 @@ +# Data Protection & Compliance Maintenance + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-18) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_DPO}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the ongoing maintenance of the legal/compliance register, the record of processing activities (RoPA), deletion periods/deletion concept and the handling of data subject rights. It operationalises the associated policy ({{LINK:R14}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for all processing of personal data as well as legal/contractual requirements. + +## 3. Trigger + +Regular review, new legal/contractual requirement, data subject request, new or changed processing. + +## 4. Inputs + +- Legal/compliance register (ISMS tool, {{TOOL_NAME}}) +- Record of processing activities (RoPA) +- Deletion concept ({{LINK:BASELINE}}, BL-DEL-01) + +## 5. Process + +1. Review and update the legal/compliance register regularly ({{REVIEW_CYCLE}}). +2. Maintain the record of processing activities (RoPA) in the ISMS tool ({{TOOL_NAME}}). +3. Implement and monitor deletion periods and the deletion concept (BL-DEL-01). +4. Handle data subject rights on time; document the processing and the result. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Maintain legal/compliance register | {{ROLE_DPO}} | {{ROLE_ISB}} | Business unit | - | +| 2 | Maintain RoPA | {{ROLE_DPO}} | {{ROLE_DPO}} | Business unit | - | +| 3 | Implement/monitor deletion periods | {{ROLE_IT_LEAD}} | {{ROLE_DPO}} | {{ROLE_ISB}} | - | +| 4 | Handle data subject rights | {{ROLE_DPO}} | {{ROLE_DPO}} | {{ROLE_ISB}} | - | + +## 7. Result & evidence + +Up-to-date legal/compliance register and RoPA, deletion evidence, documented data subject requests. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Up-to-dateness of the legal/compliance register +- Data subject requests handled on time +- Overdue deletions + +## 9. Related documents + +- Associated policy: {{LINK:R14}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-19_Informationssicherheit-in-Projekten.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-19_Informationssicherheit-in-Projekten.md new file mode 100644 index 0000000..1dee0c0 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-19_Informationssicherheit-in-Projekten.md @@ -0,0 +1,70 @@ +# Information Security in Projects + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-19) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure ensures that information security is taken into account in projects from the outset: project classification, risk assessment in an early phase and upon changes, derivation and tracking of measures as well as involvement of the ISO where the protection need is elevated. It operationalises the associated policy ({{LINK:R01}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for all projects relating to information, IT systems or business processes. + +## 3. Trigger + +Project start, substantial project change, project completion. + +## 4. Inputs + +- Catalogue of criteria for project classification ({{LINK:BASELINE}}, BL-PROJ-01) +- Project register ({{LINK:REG-PROJECTS}}) +- Risk assessment scale / risk register + +## 5. Process + +1. At the outset, classify the project with regard to its information security need on the basis of the **documented catalogue of criteria (BL-PROJ-01)**; entry in the **project register ({{LINK:REG-PROJECTS}})**. +2. Carry out a risk assessment in an early project phase and upon changes (coupling with risk management {{LINK:VA-09}}). +3. Derive measures and track them as tasks in {{TOOL_TICKET}}. +4. {{#if FLAG_ELEVATED_PROTECTION}} Where the protection need is elevated, {{ROLE_ISB}} is involved; additional reviews/approvals take place before critical milestones.{{/if}} +5. Before project completion, review the implementation of the measures and document it in the project register. + +## 6. RACI + +| # | Step | R (Execution) | A (Accountable) | C (Consulted) | I (Informed) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Classify the project | Project management | {{ROLE_ISB}} | {{ROLE_ISB}} | - | +| 2 | Carry out risk assessment | Project management | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Derive & track measures | Project management | Project management | {{ROLE_ISB}} | - | +| 4 | ISO involvement (elevated protection need) | {{ROLE_ISB}} | {{ROLE_ISB}} | Project management | {{ROLE_MANAGEMENT}} | +| 5 | Final review of measures | Project management | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Maintained project register with classification, risk assessment and measure status. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of classified projects +- Open project security measures +- Share of projects with ISO involvement where the protection need is elevated + +## 9. Related documents + +- Associated policy: {{LINK:R01}} +- Register: {{LINK:REG-PROJECTS}} +- Risk management procedure: {{LINK:VA-09}} +- Technical security baseline: {{LINK:BASELINE}} +- ISA mapping matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md new file mode 100644 index 0000000..4f3bd2a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md @@ -0,0 +1,38 @@ +# Prototype Access and Transport + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-20) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure operationalises the Prototype Protection policy ({{LINK:P01}}). It governs access to prototype areas as well as the transport and storage of prototypes so that confidentiality and integrity are ensured. + +## 2. Scope + +The procedure applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) for all persons and areas involved with prototypes. + +## 3. Process + +### 3.1 Access + +- Access to prototype areas only for individually authorised persons; visitors are escorted and logged. +- Access rights are reviewed regularly and revoked where necessary. + +### 3.2 Transport and storage + +- Transport in secured, sealed containers with logged handover. +- Storage in secured zones with access and visual protection; check-in and check-out are documented in a traceable manner. + +## 4. Evidence + +Access, handover and storage logs are maintained in accordance with the evidence register ({{LINK:NACHWEISREGISTER}}). diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md new file mode 100644 index 0000000..4fe289f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md @@ -0,0 +1,78 @@ +# Nonconformities & Corrective Actions + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-21) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs the recording, root cause analysis, treatment and effectiveness review of nonconformities and the continual improvement of the ISMS derived from them. It elaborates the corresponding policy ({{LINK:R03}}). + +> The procedure also carries the requirement to correct and follow up deviations, as required by the compliance review in security operations ({{LINK:VA-15}}) — it therefore applies regardless of which framework the organisation follows. + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) to all nonconformities against policies, procedures, technical requirements as well as legal and contractual obligations. + +## 3. Trigger + +Audit finding, result of a compliance review, security incident, deviation of a metric from its target value, report from operations or third parties, observation during the management review. + +## 4. Inputs + +- Audit reports and findings ({{LINK:VA-15}}) +- Incidents and lessons learned ({{LINK:VA-01}}) +- Metrics deviating from their target value ({{LINK:VA-22}}) +- Risk register and risk treatment plan ({{LINK:VA-09}}) + +## 5. Process + +1. **Record:** create the nonconformity in the ISMS tool ({{TOOL_NAME}}) with origin, description and affected area. +2. **Respond immediately:** decide the correction to control the deviation and how to deal with its consequences. +3. **Analyse the cause:** determine the cause and evaluate whether similar nonconformities exist or could occur elsewhere. +4. **Define corrective action:** decide the action with a responsible role and a due date; size it to the cause, not to the symptom. +5. **Implement and follow up:** track implementation in {{TOOL_NAME}}; delay escalates to {{ROLE_ISB}}. +6. **Review effectiveness:** after the defined effectiveness interval, verify that the cause has been eliminated; adjust risks, controls and documents where necessary. +7. **Close:** document and retain the nature of the nonconformity, the actions taken and the result of the effectiveness review. + +## 6. RACI + +| # | Step | R (execution) | A (accountable) | C (consulted) | I (informed) | +|---|------|---------------|-----------------|---------------|--------------| +| 1 | Record | Reporting person / auditor | {{ROLE_ISB}} | - | - | +| 2 | Respond immediately | Business unit | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Analyse the cause | {{ROLE_ISB}} | {{ROLE_ISB}} | Business unit | - | +| 4 | Define corrective action | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | Business unit | - | +| 5 | Implement and follow up | Action owner | {{ROLE_ISB}} | - | {{ROLE_MANAGEMENT}} | +| 6 | Review effectiveness | {{ROLE_ISB}} | {{ROLE_ISB}} | Business unit | {{ROLE_MANAGEMENT}} | +| 7 | Close | {{ROLE_ISB}} | {{ROLE_ISB}} | - | - | + +## 7. Result & evidence + +Action register with root cause analysis, due dates and documented effectiveness review in {{TOOL_NAME}}. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Number of open nonconformities by age +- On-time completion of corrective actions +- Share of actions with confirmed effectiveness +- Recurrence rate of similar nonconformities + +## 9. Related documents + +- Corresponding policy: {{LINK:R03}} +- Internal audits: {{LINK:VA-15}} +- Management review and metrics: {{LINK:VA-22}} +- Incident response: {{LINK:VA-01}} +- Technical security baseline: {{LINK:BASELINE}} + + diff --git a/seed/isms-vorlagenpaket-v2-en/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md new file mode 100644 index 0000000..81d8293 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2-en/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md @@ -0,0 +1,77 @@ +# Management Review & Metrics + +| Document information | Value | +|-----------------------|------| +| Document type | Procedure instruction (VA-22) | +| Scope | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Process owner | {{ROLE_ISB}} | +| Approved by | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Date | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Purpose + +This procedure governs how information security performance is measured and evaluated and how top management reviews the ISMS at planned intervals. It elaborates the corresponding policy ({{LINK:R03}}). + +## 2. Scope + +Applies within the ISMS scope ({{ISMS_SCOPE_DESCRIPTION}}) to all information security metrics and to the management review of the ISMS. + +## 3. Trigger + +Measurement interval of the respective metric, date of the management review (BL-GOV-02), significant changes within the scope, severe incident. + +## 4. Inputs + +- Metrics sheet with target values and owners ({{TOOL_NAME}}) +- Audit results and open findings ({{LINK:VA-15}}) +- Nonconformities and corrective actions ({{LINK:VA-21}}) +- Risk assessment and status of the risk treatment plan ({{LINK:VA-09}}) +- Incidents and reporting obligations ({{LINK:VA-01}}) +- Feedback from interested parties + +## 5. Process + +1. **Define metrics:** for each metric determine what is measured, by which method and data source, at which interval, who measures, when it is analysed and who analyses it. +2. **Measure:** collect the values at the defined interval and record them in {{TOOL_NAME}}. +3. **Analyse:** evaluate the results against the target values and form trends; a deviation from the target value raises a nonconformity ({{LINK:VA-21}}). +4. **Prepare the management review:** compile the inputs — status of actions from previous reviews, changes in relevant internal and external issues and in the requirements of interested parties, feedback on information security performance, feedback from interested parties, results of the risk assessment, opportunities for improvement. +5. **Conduct the review:** {{ROLE_MANAGEMENT}} reviews the ISMS at the interval {{MGMT_REVIEW_CYCLE}} against the fixed agenda (BL-GOV-02). +6. **Take decisions:** decisions on opportunities for improvement and on any need to change the ISMS, each with a responsible role and a due date. +7. **Record and follow up:** retain the minutes in {{TOOL_NAME}}; track the decisions through to completion. + +## 6. RACI + +| # | Step | R (execution) | A (accountable) | C (consulted) | I (informed) | +|---|------|---------------|-----------------|---------------|--------------| +| 1 | Define metrics | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | {{ROLE_IT_LEAD}} | Business units | +| 2 | Measure | Metric owner | {{ROLE_ISB}} | - | - | +| 3 | Analyse | {{ROLE_ISB}} | {{ROLE_ISB}} | Business unit | - | +| 4 | Prepare the review | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 5 | Conduct the review | {{ROLE_MANAGEMENT}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | Business units | +| 6 | Take decisions | {{ROLE_MANAGEMENT}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 7 | Record and follow up | {{ROLE_ISB}} | {{ROLE_ISB}} | - | {{ROLE_MANAGEMENT}} | + +## 7. Result & evidence + +A maintained metrics sheet with measured values per period and minutes of the management review with decisions, owners and due dates. Evidence is referenced in the central evidence register ({{LINK:NACHWEISREGISTER}}). + +## 8. Key performance indicators (KPI) + +- Share of metrics actually collected at the defined interval +- Share of metrics within their target value +- On-time completion of decisions from the management review + +## 9. Related documents + +- Corresponding policy: {{LINK:R03}} +- Nonconformities and corrective actions: {{LINK:VA-21}} +- Internal audits: {{LINK:VA-15}} +- Risk management procedure: {{LINK:VA-09}} +- Technical security baseline: {{LINK:BASELINE}} + + diff --git a/seed/isms-vorlagenpaket-v2/00_Integrationsleitfaden_Wizard.md b/seed/isms-vorlagenpaket-v2/00_Integrationsleitfaden_Wizard.md new file mode 100644 index 0000000..b6c88fc --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/00_Integrationsleitfaden_Wizard.md @@ -0,0 +1,148 @@ +# Integrationsleitfaden für den Programmierer – ISMS-Vorlagenpaket v2 + +Dieses Dokument beschreibt, wie die Richtlinien-Templates, Variablen, das versteckte Anforderungs-Mapping und die Verlinkungen in den Wizard/das Tool eingebaut werden. Zielgruppe: die Person, die den Wizard implementiert. + +## 1. Paketstruktur + +``` +ISMS-Vorlagenpaket-v2/ +├── 00_Integrationsleitfaden_Wizard.md ← dieses Dokument +├── variables.schema.json ← alle Wizard-Variablen (Single Source of Truth) +├── mapping.json ← Anforderungs-Mapping (REQ/IMPL ↔ ISA-Control ↔ Richtlinie) +├── ISA-Mapping-Matrix.md ← menschenlesbare ISA-Matrix (ersetzt "Bezug zu VDA ISA") +├── Technische-Sicherheits-Baseline.md ← zentrale konkrete Parameter (BL-IDs), einzige Pflegestelle +├── Nachweisregister_zentral.md ← zentrales Nachweis-Template +├── richtlinien/ +│ ├── L00_Informationssicherheitsleitlinie.md +│ └── R01 … R14 +└── verfahren/ + └── VA-01 … VA-13 ← Verfahrensanweisungen (Abläufe zu den Richtlinien) +``` + +**Richtlinie vs. Verfahren:** Die Richtlinie (R01–R14) sagt *was* gilt und *wie* es grundsätzlich umgesetzt ist. Die Verfahrensanweisung (VA-01–VA-13) beschreibt den konkreten *Ablauf* (Auslöser → Schritte → RACI → Ergebnis/Nachweis). Jedes Verfahren trägt einen Hidden-Anker ``; die erfüllten Anforderungen sind zusätzlich je Eintrag in `mapping.json` (`verfahren`-Liste) und je Anforderung (`verfahren`-Feld) hinterlegt. So fließen Verfahren automatisch in die Nachweisdokumentation ein. + +## 2. Vier Bausteine im Überblick + +1. **Variablen** (`{{NAME}}`, UPPER_SNAKE) – organisationsspezifische Werte, aus `variables.schema.json`. +2. **Bedingungsblöcke** (`{{#if FLAG_X}} … {{/if}}`) – blenden Anforderungen/Abschnitte je nach Feature-Flag und Reifegrad ein/aus. +3. **Hidden-Anker** (`` / ``) – unsichtbare IDs je Einzelanforderung; Grundlage für Nachweis-Mapping und Deep-Links. +4. **Link-Platzhalter** (`{{LINK:ZIEL}}`) – Verweise zwischen Dokumenten und zu Nachweisen, die das Tool zur Laufzeit auflöst. + +## 3. Templating-Konvention (Handlebars-kompatibel) + +| Konstrukt | Bedeutung | +|-----------|-----------| +| `{{ORG_NAME}}` | Variablen-Einsetzung | +| `{{#if FLAG_CLOUD_USED}} … {{/if}}` | bedingter Block (Feature-Flag) | +| `{{#if FLAG_INCLUDE_SHOULD}} … {{/if}}` | SOLL-Anforderungen ein-/ausblenden (Reifegrad) | +| `[MUSS]` / `[SOLL]` | Text-Kennzeichnung der Anforderungsstufe | +| `` | Hidden-Anker vor einer Anforderung | +| `` | Hidden-Anker vor dem zugehörigen Umsetzungstext | +| `{{LINK:R02}}` | Link-Platzhalter (siehe Abschnitt 6) | + +Beim Rendern: Variablen einsetzen, `{{#if}}`-Blöcke nach Kontext auflösen, `{{LINK:…}}` in echte Links übersetzen. Die ``-Anker **im Dokument belassen** (sie sind im Lesemodus unsichtbar) – das Tool braucht sie zur Laufzeit für Deep-Links und Nachweiszuordnung. Für den PDF-/Druckexport können sie entfernt werden. + +## 4. Aufbau einer thematischen Richtlinie (R01–R14) + +``` +### 3.1 (ISA 1.2.1) + +**Anforderung** + +- **[MUSS]** +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** +{{/if}} + +**Umsetzung bei {{ORG_NAME}}** + + +``` + +Jede Anforderung (`REQ`) hat genau eine Umsetzung (`IMPL`) mit identischer ID. Ausnahme **L00** (Leitlinie): kombiniertes Dokument, dort ist `IMPL`-Anker = `REQ`-Anker (in `mapping.json` bereits so hinterlegt). + +**ID-Schema:** `-`, z. B. `1.2.1-M1`, `5.2.9-S1`. MUSS und SOLL werden getrennt nummeriert. + +## 5. `mapping.json` – das versteckte Anforderungs-Mapping + +Zentrale Datei, die je Einzelanforderung Metadaten bündelt. Aufbau je Eintrag: + +```json +{ + "id": "1.2.1-M1", + "policy": "R01", + "policy_file": "R01_ISMS-Organisation-und-Rollen.md", + "control": "1.2.1", + "type": "MUSS", + "req_anchor": "REQ 1.2.1-M1", + "impl_anchor": "IMPL 1.2.1-M1", + "condition": null, + "requirement": "Der Geltungsbereich des ISMS … ist bestimmt und dokumentiert.", + "implementation": "Der ISMS-Geltungsbereich ist im ISMS-Tool … dokumentiert.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}" +} +``` + +- `condition` = `null` (immer aktiv), `"FLAG_INCLUDE_SHOULD"` (nur bei SOLL) oder ein Feature-Flag. Anforderungen, deren Bedingung im Kontext `false` ist, erscheinen im Dokument nicht und werden in der Nachweisdoku übersprungen. +- **Reading-Mode:** Der Anwender sieht nur Anforderung + Umsetzung, keine IDs. Das Tool blendet je Anforderung eine dezente Verlinkung („Nachweise") ein, die über `nachweis_link` bzw. die ID auf den Nachweiseintrag zeigt. + +## 6. Link-Platzhalter `{{LINK:ZIEL}}` auflösen + +Das Tool ersetzt Platzhalter durch echte Deep-Links (unabhängig von Dateipfaden): + +| Platzhalter | Ziel | +|-------------|------| +| `{{LINK:L00}}` … `{{LINK:R14}}` | jeweiliges Richtlinien-Dokument | +| `{{LINK:R01#1.2.1}}` | Sprungziel auf Control-Abschnitt (Anker aus ID ableitbar) | +| `{{LINK:NACHWEISREGISTER}}` | zentrales Nachweisregister | +| `{{LINK:ISA_MAPPING}}` | ISA-Mapping-Matrix | +| `{{LINK:BASELINE}}` | Technische Sicherheits-Baseline | +| `{{LINK:VA-01}}` … `{{LINK:VA-13}}` | Verfahrensanweisungen | + +**Konkrete Parameter (Passwort, Fristen, Krypto …):** liegen ausschließlich in `Technische-Sicherheits-Baseline.md` und im Schema (Variablen wie `PW_MIN_LENGTH`, `LOG_RETENTION`). Die Umsetzungstexte referenzieren die Baseline-IDs (`BL-IAM-01` …) und rendern die Werte über dieselben Variablen – so gibt es genau eine Pflegestelle je Wert. + +Empfehlung: eine Auflösungstabelle `DOC_ID → interne Tool-URL` pflegen; unbekannte Ziele als Warnung loggen. + +## 7. Wizard-Ablauf (empfohlen) + +1. **Schema laden** (`variables.schema.json`) → Eingabemasken erzeugen. Reihenfolge: Organisation → Geltungsbereich → Rollen → ISMS-Tool → Feature-Flags → Reifegrad → tech. Lösungen (TECH_*) → Metadaten. +2. **Kontext validieren** (Pflichtfelder `required`, Defaults übernehmen). +3. **Rendern** je Dokument: Variablen einsetzen, `{{#if}}` auflösen, `{{LINK}}` übersetzen, Hidden-Anker belassen. +4. **Mapping filtern**: aus `mapping.json` alle Anforderungen entfernen, deren `condition` im Kontext `false` ist → ergibt die **aktive Anforderungsliste** dieses Mandanten. +5. **Speichern/Verknüpfen** im Tool. + +### Minimal-Render (Node/Handlebars) + +```js +import Handlebars from "handlebars"; +const render = (tpl, ctx) => + Handlebars.compile(tpl, { noEscape: true })(ctx) // Hidden-Anker bleiben erhalten + .replace(/\{\{LINK:([^}]+)\}\}/g, (_, id) => resolveLink(id)); +``` + +## 8. Nachweisdokumentation aus dem Mapping bauen + +Genau der Zweck des Mappings: Aus `mapping.json` + Nachweiseinträgen lässt sich per Knopfdruck eine Nachweisdoku erzeugen. Vorgehen: + +1. Aktive Anforderungen ermitteln (Abschnitt 7, Schritt 4). +2. Je Anforderung: `id`, `type`, `requirement`, `implementation`, Link zur Richtlinie (`link`) und zum Nachweis (`nachweis_link`) zusammenstellen. +3. Nachweise aus {{TOOL_NAME}} anhängen (Owner/Turnus aus `Nachweisregister_zentral.md`). +4. Ausgabe als Tabelle/Export (z. B. für das VDA-ISA-Assessment: Spalten „Implementation description" = `implementation`, „Reference documentation" = Nachweis-Link). + +So entsteht die Assessment-Sicht, ohne dass der Anwender im Lesemodus mit IDs konfrontiert wird. + +## 9. Cross-Links zwischen Dokumenten + +Jede Richtlinie enthält einen Abschnitt **„Verwandte Dokumente"** mit `{{LINK:…}}` auf Leitlinie, ISA-Matrix, Nachweisregister und thematisch verwandte Richtlinien. Innerhalb der Umsetzungstexte stehen zusätzlich kontextbezogene Verweise (z. B. R08 verweist bei Zugriffsrechten auf R10). Das Tool löst alle Platzhalter einheitlich auf. + +## 10. Pflege & Konsistenz + +- **Neue Variable:** zuerst in `variables.schema.json`, dann im Template verwenden. +- **Neue Anforderung/Control:** Anforderung + Umsetzung im Template ergänzen (mit `REQ`/`IMPL`-Ankern) **und** Eintrag in `mapping.json`; ISA-Matrix neu erzeugen. +- **Konsistenzcheck vor Auslieferung (empfohlen):** (a) jeder `{{NAME}}` existiert im Schema; (b) jeder `REQ`/`IMPL`-Anker im Dokument hat einen `mapping.json`-Eintrag und umgekehrt; (c) jedes `{{LINK:…}}`-Ziel ist auflösbar. Die mitgelieferten Generatoren (`_generate_v2.py`, `_matrix.py`) sind die Referenzimplementierung dieser Regeln. + +## 11. Reifegrad + +`FLAG_INCLUDE_SHOULD = true` → Reifegrad 3 (MUSS + SOLL). `false` → reines MUSS-Set. Höhere Reifegrade (4/5) lassen sich später als zusätzliche `condition`-Stufe (z. B. `FLAG_LEVEL_4`) ergänzen, ohne die Struktur zu ändern. diff --git a/seed/isms-vorlagenpaket-v2/ISA-Mapping-Matrix.md b/seed/isms-vorlagenpaket-v2/ISA-Mapping-Matrix.md new file mode 100644 index 0000000..c949f2e --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/ISA-Mapping-Matrix.md @@ -0,0 +1,379 @@ +# ISA-Mapping-Matrix - VDA ISA 2027 (Information Security) + +Zentrale Zuordnung **ISA-Control -> Richtlinie -> Einzelanforderungen** über alle Schutzbedarf-Ebenen (MUSS/SOLL/HOCH/SEHR HOCH). Anforderungen 1:1 aus der ISA übernommen; Kopplung über `mapping.json` und Hidden-Anker. Verweise: {{LINK:NACHWEISREGISTER}}, {{LINK:BASELINE}}. + +| ISA | Richtlinie | MUSS | SOLL | HOCH | SEHR HOCH | Verfahren | +|-----|-----------|------|------|------|-----------|-----------| +| 1.1.1 | {{LINK:L00}} Informationssicherheitsleitlinie | 5 | 4 | 0 | 0 | - | +| 1.2.1 | {{LINK:R01}} ISMS-Organisation und Rollen | 6 | 0 | 0 | 0 | - | +| 1.2.2 | {{LINK:R01}} ISMS-Organisation und Rollen | 4 | 2 | 1 | 0 | - | +| 1.2.3 | {{LINK:R01}} ISMS-Organisation und Rollen | 1 | 3 | 1 | 0 | - | +| 1.3.1 | {{LINK:R02}} Asset- und Klassifizierung | 2 | 1 | 0 | 0 | VA-08 | +| 1.3.2 | {{LINK:R02}} Asset- und Klassifizierung | 3 | 1 | 0 | 0 | VA-08 | +| 1.3.3 | {{LINK:R02}} Asset- und Klassifizierung | 2 | 4 | 0 | 0 | - | +| 1.3.4 | {{LINK:R02}} Asset- und Klassifizierung | 2 | 5 | 0 | 1 | - | +| 1.4.1 | {{LINK:R03}} Risikomanagement und Audit | 4 | 4 | 0 | 0 | VA-09 | +| 1.5.1 | {{LINK:R03}} Risikomanagement und Audit | 5 | 1 | 0 | 0 | - | +| 1.5.2 | {{LINK:R03}} Risikomanagement und Audit | 2 | 1 | 0 | 0 | - | +| 1.6.1 | {{LINK:R04}} Incident, Notfall und Kontinuität | 3 | 6 | 0 | 1 | VA-01 | +| 1.6.2 | {{LINK:R04}} Incident, Notfall und Kontinuität | 3 | 3 | 5 | 1 | VA-01 | +| 1.6.3 | {{LINK:R04}} Incident, Notfall und Kontinuität | 3 | 6 | 5 | 1 | VA-02 | +| 2.1.1 | {{LINK:R05}} Personalsicherheit und Awareness | 3 | 2 | 0 | 0 | - | +| 2.1.2 | {{LINK:R05}} Personalsicherheit und Awareness | 2 | 3 | 0 | 0 | - | +| 2.1.3 | {{LINK:R05}} Personalsicherheit und Awareness | 1 | 6 | 0 | 0 | VA-12 | +| 2.1.4 | {{LINK:R06}} Mobiles Arbeiten und mobile Geräte | 1 | 2 | 1 | 0 | - | +| 3.1.1 | {{LINK:R07}} Physische Sicherheit | 3 | 5 | 1 | 0 | - | +| 3.1.4 | {{LINK:R06}} Mobiles Arbeiten und mobile Geräte | 1 | 1 | 1 | 0 | - | +| 4.1.1 | {{LINK:R08}} Identitäts- und Zugriffsmanagement | 1 | 1 | 1 | 0 | VA-03 | +| 4.1.2 | {{LINK:R08}} Identitäts- und Zugriffsmanagement | 2 | 3 | 1 | 1 | - | +| 4.1.3 | {{LINK:R08}} Identitäts- und Zugriffsmanagement | 7 | 10 | 0 | 0 | VA-03 | +| 4.2.1 | {{LINK:R08}} Identitäts- und Zugriffsmanagement | 2 | 5 | 1 | 2 | VA-03 | +| 5.1.1 | {{LINK:R09}} Kryptografie und Übertragung | 1 | 1 | 1 | 0 | VA-07 | +| 5.1.2 | {{LINK:R09}} Kryptografie und Übertragung | 3 | 3 | 1 | 1 | VA-07 | +| 5.2.1 | {{LINK:R10}} Betriebssicherheit | 1 | 4 | 1 | 0 | VA-04 | +| 5.2.2 | {{LINK:R10}} Betriebssicherheit | 2 | 1 | 0 | 0 | - | +| 5.2.3 | {{LINK:R10}} Betriebssicherheit | 2 | 8 | 0 | 0 | - | +| 5.2.4 | {{LINK:R10}} Betriebssicherheit | 5 | 3 | 2 | 1 | VA-13 | +| 5.2.5 | {{LINK:R10}} Betriebssicherheit | 3 | 3 | 0 | 0 | VA-04, VA-06 | +| 5.2.6 | {{LINK:R10}} Betriebssicherheit | 5 | 3 | 1 | 1 | VA-06 | +| 5.2.7 | {{LINK:R10}} Betriebssicherheit | 2 | 2 | 1 | 0 | - | +| 5.2.8 | {{LINK:R04}} Incident, Notfall und Kontinuität | 2 | 3 | 7 | 3 | VA-02 | +| 5.2.9 | {{LINK:R10}} Betriebssicherheit | 2 | 1 | 2 | 3 | VA-05 | +| 5.3.1 | {{LINK:R11}} Sichere Beschaffung und Entwicklung | 4 | 5 | 0 | 1 | - | +| 5.3.2 | {{LINK:R11}} Sichere Beschaffung und Entwicklung | 1 | 3 | 1 | 0 | - | +| 5.3.3 | {{LINK:R11}} Sichere Beschaffung und Entwicklung | 0 | 1 | 0 | 0 | - | +| 5.3.4 | {{LINK:R12}} Cloud-, KI- und externe IT-Dienste | 1 | 1 | 0 | 0 | VA-11 | +| 5.3.4-KI | {{LINK:R12}} Cloud-, KI- und externe IT-Dienste | 3 | 1 | 0 | 0 | VA-11 | +| 6.1.1 | {{LINK:R13}} Lieferanten- und Dienstleistersteuerung | 3 | 2 | 3 | 2 | VA-10 | +| 6.1.2 | {{LINK:R13}} Lieferanten- und Dienstleistersteuerung | 4 | 5 | 0 | 0 | VA-10 | +| 6.1.3 | {{LINK:R13}} Lieferanten- und Dienstleistersteuerung | 5 | 2 | 5 | 0 | VA-10 | +| 7.1.1 | {{LINK:R14}} Compliance und Datenschutz | 2 | 1 | 0 | 0 | - | +| 7.1.2 | {{LINK:R14}} Compliance und Datenschutz | 3 | 0 | 0 | 0 | - | + +**Summe:** 316 Anforderungen (MUSS 122, SOLL 132, HOCH 43, SEHR HOCH 19) — davon 312 1:1 aus VDA ISA und 4 kundenspezifische Ergänzung (KI). Controls: 45. + +> 3.1.2 in ISA 2027 als 'Superseded by 1.6.3, 5.2.8 und 5.2.9' entfallen - abgedeckt über {{LINK:R04}} und {{LINK:R10}}. + +## Detailzuordnung je Anforderung + +| ID | Ebene | Richtlinie | Anforderung (Kurz) | Bedingung | +|----|-------|-----------|--------------------|-----------| +| 1.1.1-M1 | MUSS | L00 | Die Anforderungen der Informationssicherheit sind bestimmt, dokumentiert und an den Zielen... | - | +| 1.1.1-M2 | MUSS | L00 | Eine Leitlinie existiert und ist durch die Leitung der Organisation genehmigt. | - | +| 1.1.1-M3 | MUSS | L00 | Die Leitlinie benennt Ziele und die Bedeutung der Informationssicherheit innerhalb der Org... | - | +| 1.1.1-M4 | MUSS | L00 | Die Leitlinien werden den Beschäftigten in geeigneter Form zur Verfügung gestellt (z. B. I... | - | +| 1.1.1-M5 | MUSS | L00 | Beschäftigte und externe Geschäftspartner werden über für sie relevante Änderungen informi... | - | +| 1.1.1-S1 | SOLL | L00 | Die Informationssicherheitsanforderungen basieren auf der Strategie der Organisation; Gese... | FLAG_INCLUDE_SHOULD | +| 1.1.1-S2 | SOLL | L00 | Die Leitlinie benennt Konsequenzen bei Nichteinhaltung. | FLAG_INCLUDE_SHOULD | +| 1.1.1-S3 | SOLL | L00 | Weitere relevante Sicherheitsrichtlinien sind etabliert. | FLAG_INCLUDE_SHOULD | +| 1.1.1-S4 | SOLL | L00 | Regelmäßige Überprüfung und ggf. Überarbeitung der Richtlinien sind etabliert. | FLAG_INCLUDE_SHOULD | +| 1.2.1-M1 | MUSS | R01 | Der Geltungsbereich des ISMS (die durch das ISMS gesteuerte Organisation) ist definiert. | - | +| 1.2.1-M2 | MUSS | R01 | Die Anforderungen der Organisation an das ISMS sind bestimmt. | - | +| 1.2.1-M3 | MUSS | R01 | Die Organisationsleitung hat das ISMS beauftragt und genehmigt. | - | +| 1.2.1-M4 | MUSS | R01 | Das ISMS stellt der Organisationsleitung geeignete Mittel zur Überwachung und Steuerung be... | - | +| 1.2.1-M5 | MUSS | R01 | Die anwendbaren Controls sind bestimmt (z. B. ISO-27001-Anwendbarkeitserklärung oder ausge... | - | +| 1.2.1-M6 | MUSS | R01 | Die Wirksamkeit des ISMS wird regelmäßig durch die Leitung überprüft. | - | +| 1.2.2-M1 | MUSS | R01 | Verantwortlichkeiten für Informationssicherheit sind definiert, dokumentiert und zugewiese... | - | +| 1.2.2-M2 | MUSS | R01 | Die verantwortlichen Beschäftigten sind definiert, qualifiziert und für ihre Aufgabe befäh... | - | +| 1.2.2-M3 | MUSS | R01 | Die erforderlichen Ressourcen stehen zur Verfügung. | - | +| 1.2.2-M4 | MUSS | R01 | Die Ansprechpartner sind innerhalb der Organisation und relevanten Geschäftspartnern bekan... | - | +| 1.2.2-S1 | SOLL | R01 | Es besteht eine Definition und Dokumentation einer angemessenen Informationssicherheitsstr... | FLAG_INCLUDE_SHOULD | +| 1.2.2-S2 | SOLL | R01 | Sicherheitsrelevante Rollen, die nicht Teil des ISMS, aber für die Informationssicherheit ... | FLAG_INCLUDE_SHOULD | +| 1.2.2-H1 | HOCH | R01 | Eine angemessene organisatorische Trennung von Verantwortlichkeiten ist etabliert, um Inte... | FLAG_HIGH_PROTECTION | +| 1.2.3-M1 | MUSS | R01 | Projekte werden unter Berücksichtigung der Informationssicherheitsanforderungen klassifizi... | - | +| 1.2.3-S1 | SOLL | R01 | Verfahren und Kriterien für die Klassifizierung von Projekten sind dokumentiert. | FLAG_INCLUDE_SHOULD | +| 1.2.3-S2 | SOLL | R01 | In einer frühen Projektphase wird eine Risikobewertung nach dem definierten Verfahren durc... | FLAG_INCLUDE_SHOULD | +| 1.2.3-S3 | SOLL | R01 | Für identifizierte Informationssicherheitsrisiken werden Maßnahmen abgeleitet und im Proje... | FLAG_INCLUDE_SHOULD | +| 1.2.3-H1 | HOCH | R01 | Die abgeleiteten Maßnahmen werden während des Projekts regelmäßig überprüft und bei Änderu... | FLAG_HIGH_PROTECTION | +| 1.3.1-M1 | MUSS | R02 | Informationswerte und weitere sicherheitsrelevante Assets der Organisation sind identifizi... | - | +| 1.3.1-M2 | MUSS | R02 | Die unterstützenden Assets, die die Informationswerte verarbeiten, sind identifiziert und ... | - | +| 1.3.1-S1 | SOLL | R02 | Ein Katalog der relevanten Informationswerte existiert; dabei werden die einschlägigen Asp... | FLAG_INCLUDE_SHOULD | +| 1.3.2-M1 | MUSS | R02 | Ein konsistentes Schema zur Klassifizierung von Informationswerten hinsichtlich des Schutz... | - | +| 1.3.2-M2 | MUSS | R02 | Die Bewertung der identifizierten Informationswerte erfolgt nach den definierten Kriterien... | - | +| 1.3.2-M3 | MUSS | R02 | Vorgaben zur Handhabung unterstützender Assets (z. B. Kennzeichnung, Nutzung, Transport, S... | - | +| 1.3.2-S1 | SOLL | R02 | Die Schutzziele Integrität und Verfügbarkeit werden berücksichtigt. | FLAG_INCLUDE_SHOULD | +| 1.3.3-M1 | MUSS | R02 | Externe IT-Dienste werden nicht ohne ausdrückliche Bewertung und Umsetzung der Information... | - | +| 1.3.3-M2 | MUSS | R02 | Die externen IT-Dienste sind mit dem Schutzbedarf der verarbeiteten Informationswerte abge... | - | +| 1.3.3-S1 | SOLL | R02 | Anforderungen an Beschaffung, Inbetriebnahme und Freigabe im Zusammenhang mit der Nutzung ... | FLAG_INCLUDE_SHOULD | +| 1.3.3-S2 | SOLL | R02 | Ein Verfahren zur Freigabe unter Berücksichtigung des Schutzbedarfs ist etabliert. | FLAG_INCLUDE_SHOULD | +| 1.3.3-S3 | SOLL | R02 | Externe IT-Dienste und ihre Freigabe sind dokumentiert. | FLAG_INCLUDE_SHOULD | +| 1.3.3-S4 | SOLL | R02 | Es wird regelmäßig überprüft, dass nur freigegebene externe IT-Dienste genutzt werden. | FLAG_INCLUDE_SHOULD | +| 1.3.4-M1 | MUSS | R02 | Software wird vor Installation oder Nutzung freigegeben; dabei werden die einschlägigen As... | - | +| 1.3.4-M2 | MUSS | R02 | Die Softwarefreigabe gilt auch für Spezialsoftware wie Wartungswerkzeuge. | - | +| 1.3.4-S1 | SOLL | R02 | Die zu verwaltenden Softwarearten (Firmware, Betriebssysteme, Anwendungen, Bibliotheken, G... | FLAG_INCLUDE_SHOULD | +| 1.3.4-S2 | SOLL | R02 | Repositorys der verwalteten Software existieren. | FLAG_INCLUDE_SHOULD | +| 1.3.4-S3 | SOLL | R02 | Die Software-Repositorys sind gegen unbefugte Manipulation geschützt. | FLAG_INCLUDE_SHOULD | +| 1.3.4-S4 | SOLL | R02 | Die Freigabe von Software wird regelmäßig überprüft. | FLAG_INCLUDE_SHOULD | +| 1.3.4-S5 | SOLL | R02 | Softwareversionen und Patch-Stände sind bekannt. | FLAG_INCLUDE_SHOULD | +| 1.3.4-V1 | SEHR HOCH | R02 | Zusätzliche Anforderungen an die Softwarenutzung (z. B. Kontroll-/Überwachungsbedarf der N... | FLAG_VERY_HIGH_PROTECTION | +| 1.4.1-M1 | MUSS | R03 | Risikobewertungen werden regelmäßig und anlassbezogen durchgeführt. | - | +| 1.4.1-M2 | MUSS | R03 | Informationssicherheitsrisiken werden angemessen bewertet (z. B. Eintrittswahrscheinlichke... | - | +| 1.4.1-M3 | MUSS | R03 | Informationssicherheitsrisiken werden dokumentiert. | - | +| 1.4.1-M4 | MUSS | R03 | Jedem Informationssicherheitsrisiko ist ein Verantwortlicher (Risk Owner) zugeordnet, der ... | - | +| 1.4.1-S1 | SOLL | R03 | Ein Verfahren zur Identifikation, Bewertung und Behandlung von Sicherheitsrisiken ist vorh... | FLAG_INCLUDE_SHOULD | +| 1.4.1-S2 | SOLL | R03 | Kriterien für Bewertung und Behandlung von Sicherheitsrisiken existieren. | FLAG_INCLUDE_SHOULD | +| 1.4.1-S3 | SOLL | R03 | Maßnahmen zur Risikobehandlung und ihre Verantwortlichen sind festgelegt und dokumentiert;... | FLAG_INCLUDE_SHOULD | +| 1.4.1-S4 | SOLL | R03 | Bei Änderungen des Umfelds (z. B. Organisationsstruktur, Standort, Regularien) erfolgt zei... | FLAG_INCLUDE_SHOULD | +| 1.5.1-M1 | MUSS | R03 | Die Einhaltung der Richtlinien wird organisationsweit überprüft. | - | +| 1.5.1-M2 | MUSS | R03 | Informationssicherheitsrichtlinien und -verfahren werden regelmäßig überprüft. | - | +| 1.5.1-M3 | MUSS | R03 | Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt. | - | +| 1.5.1-M4 | MUSS | R03 | Die Einhaltung von Informationssicherheitsanforderungen (z. B. technische Vorgaben) wird r... | - | +| 1.5.1-M5 | MUSS | R03 | Die Ergebnisse der durchgeführten Überprüfungen werden aufgezeichnet und aufbewahrt. | - | +| 1.5.1-S1 | SOLL | R03 | Ein Plan für Inhalt und Rahmenbedingungen (Zeitplan, Umfang, Controls) der durchzuführende... | FLAG_INCLUDE_SHOULD | +| 1.5.2-M1 | MUSS | R03 | Informationssicherheitsüberprüfungen werden durch eine unabhängige und kompetente Stelle r... | - | +| 1.5.2-M2 | MUSS | R03 | Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt. | - | +| 1.5.2-S1 | SOLL | R03 | Die Ergebnisse durchgeführter Überprüfungen werden dokumentiert und der Organisationsleitu... | FLAG_INCLUDE_SHOULD | +| 1.6.1-M1 | MUSS | R04 | Eine Definition für ein meldepflichtiges Sicherheitsereignis oder eine Beobachtung existie... | - | +| 1.6.1-M2 | MUSS | R04 | Angemessene, risikoorientierte Mechanismen zur Meldung von Sicherheitsereignissen sind def... | - | +| 1.6.1-M3 | MUSS | R04 | Angemessene Kanäle zur Kommunikation mit Meldenden existieren. | - | +| 1.6.1-S1 | SOLL | R04 | Eine gemeinsame Anlaufstelle für die Ereignismeldung existiert. | FLAG_INCLUDE_SHOULD | +| 1.6.1-S2 | SOLL | R04 | Verschiedene Meldekanäle je nach wahrgenommener Schwere (Echtzeit für gravierende Ereignis... | FLAG_INCLUDE_SHOULD | +| 1.6.1-S3 | SOLL | R04 | Beschäftigte sind verpflichtet und geschult, relevante Ereignisse zu melden. | FLAG_INCLUDE_SHOULD | +| 1.6.1-S4 | SOLL | R04 | Sicherheitsereignisse können auch durch Externe gemeldet werden; die einschlägigen Aspekte... | FLAG_INCLUDE_SHOULD | +| 1.6.1-S5 | SOLL | R04 | Der Mechanismus und die Information, wie Vorfälle gemeldet werden, sind für alle relevante... | FLAG_INCLUDE_SHOULD | +| 1.6.1-S6 | SOLL | R04 | Ein Rückmeldeverfahren an die Meldenden ist etabliert. | FLAG_INCLUDE_SHOULD | +| 1.6.1-V1 | SEHR HOCH | R04 | Tests und Übungen der Ereignis- und Beobachtungsmeldung werden regelmäßig durchgeführt. (C... | FLAG_VERY_HIGH_PROTECTION | +| 1.6.2-M1 | MUSS | R04 | Gemeldete Ereignisse werden ohne unangemessene Verzögerung bearbeitet. | - | +| 1.6.2-M2 | MUSS | R04 | Eine angemessene Reaktion auf gemeldete Sicherheitsereignisse ist sichergestellt. | - | +| 1.6.2-M3 | MUSS | R04 | Lessons Learned fließen in die kontinuierliche Verbesserung ein. | - | +| 1.6.2-S1 | SOLL | R04 | Gemeldete Ereignisse werden bei der Bearbeitung kategorisiert (z. B. Personal, physisch, C... | FLAG_INCLUDE_SHOULD | +| 1.6.2-S2 | SOLL | R04 | Verantwortlichkeiten für die Behandlung von Ereignissen je Kategorie sind definiert und zu... | FLAG_INCLUDE_SHOULD | +| 1.6.2-S3 | SOLL | R04 | Eine Strategie zur Meldung potenziell strafrechtlich relevanter Aspekte an zuständige Behö... | FLAG_INCLUDE_SHOULD | +| 1.6.2-H1 | HOCH | R04 | Maximale Reaktionszeiten je Klasse, Kategorie und Schwere sind definiert. (C, I, A) | FLAG_HIGH_PROTECTION | +| 1.6.2-H2 | HOCH | R04 | Nicht prioritätsgerecht bearbeitete Ereignisse werden eskaliert; die einschlägigen Aspekte... | FLAG_HIGH_PROTECTION | +| 1.6.2-H3 | HOCH | R04 | Gesetzliche, regulatorische und vertragliche Meldepflichten sowie zugehörige Kontaktinform... | FLAG_HIGH_PROTECTION | +| 1.6.2-H4 | HOCH | R04 | Eine Kommunikationsstrategie für sicherheitsrelevante Ereignisse existiert; die einschlägi... | FLAG_HIGH_PROTECTION | +| 1.6.2-H5 | HOCH | R04 | Verfahren zur Reaktion auf Sicherheitsvorfälle bei Lieferanten sind etabliert; die einschl... | FLAG_HIGH_PROTECTION | +| 1.6.2-V1 | SEHR HOCH | R04 | Die Behandlung von Ereignissen unterschiedlicher Kategorien und Prioritäten wird regelmäßi... | FLAG_VERY_HIGH_PROTECTION | +| 1.6.3-M1 | MUSS | R04 | Ein angemessener Plan zur Reaktion auf und Bewältigung von Krisensituationen existiert und... | - | +| 1.6.3-M2 | MUSS | R04 | Verantwortlichkeiten und Befugnisse für das Krisenmanagement sind definiert, dokumentiert ... | - | +| 1.6.3-M3 | MUSS | R04 | Die verantwortlichen Beschäftigten sind definiert und für ihre Aufgabe qualifiziert. | - | +| 1.6.3-S1 | SOLL | R04 | Methoden zur Erkennung von Krisensituationen sind etabliert; allgemeine Anzeichen und spez... | FLAG_INCLUDE_SHOULD | +| 1.6.3-S2 | SOLL | R04 | Ein Verfahren zur Auslösung und/oder Eskalation des Krisenmanagements ist vorhanden. | FLAG_INCLUDE_SHOULD | +| 1.6.3-S3 | SOLL | R04 | Strategische Ziele und ihre Priorität in Krisensituationen sind definiert und relevantem P... | FLAG_INCLUDE_SHOULD | +| 1.6.3-S4 | SOLL | R04 | Ein Krisenstab ist definiert und genehmigt. | FLAG_INCLUDE_SHOULD | +| 1.6.3-S5 | SOLL | R04 | Krisenrichtlinien und -verfahren sind definiert und genehmigt. | FLAG_INCLUDE_SHOULD | +| 1.6.3-S6 | SOLL | R04 | Die Krisenplanung wird regelmäßig überprüft und aktualisiert. | FLAG_INCLUDE_SHOULD | +| 1.6.3-H1 | HOCH | R04 | Relevante unterschiedliche potenzielle Krisenszenarien sind identifiziert. | FLAG_HIGH_PROTECTION | +| 1.6.3-H2 | HOCH | R04 | Notwendige Ressourcen und Informationen zur Krisenbewältigung (z. B. Kommunikationsinfrast... | FLAG_HIGH_PROTECTION | +| 1.6.3-H3 | HOCH | R04 | Eine Kommunikationsstrategie für Krisensituationen existiert. (A) | FLAG_HIGH_PROTECTION | +| 1.6.3-H4 | HOCH | R04 | Effizienz, Durchführbarkeit und Angemessenheit der Krisenplanung werden regelmäßig bewerte... | FLAG_HIGH_PROTECTION | +| 1.6.3-H5 | HOCH | R04 | Stichprobenbasierte Tests der Krisenplanung werden durchgeführt (z. B. Simulation, Tableto... | FLAG_HIGH_PROTECTION | +| 1.6.3-V1 | SEHR HOCH | R04 | Krisenübungen und Simulationen unter Einbindung aller relevanten Personen, einschließlich ... | FLAG_VERY_HIGH_PROTECTION | +| 2.1.1-M1 | MUSS | R05 | Sensible Arbeitsbereiche und Tätigkeiten sind bestimmt. | - | +| 2.1.1-M2 | MUSS | R05 | Die Anforderungen an Beschäftigte hinsichtlich ihrer Stellenprofile sind bestimmt und erfü... | - | +| 2.1.1-M3 | MUSS | R05 | Die Identität potenzieller Beschäftigter wird verifiziert (z. B. Prüfung von Ausweisdokume... | - | +| 2.1.1-S1 | SOLL | R05 | Die persönliche Eignung potenzieller Beschäftigter wird mit einfachen Methoden überprüft (... | FLAG_INCLUDE_SHOULD | +| 2.1.1-S2 | SOLL | R05 | Eine erweiterte Eignungsprüfung abhängig vom Arbeitsbereich und der Tätigkeit wird durchge... | FLAG_INCLUDE_SHOULD | +| 2.1.2-M1 | MUSS | R05 | Eine Vertraulichkeitsverpflichtung ist in Kraft. | - | +| 2.1.2-M2 | MUSS | R05 | Eine Verpflichtung zur Einhaltung der Informationssicherheitsrichtlinien ist in Kraft. | - | +| 2.1.2-S1 | SOLL | R05 | Eine über den Arbeitsvertrag hinausgehende Vertraulichkeitsverpflichtung ist in Kraft. | FLAG_INCLUDE_SHOULD | +| 2.1.2-S2 | SOLL | R05 | Informationssicherheitsaspekte werden in den Arbeitsverträgen der Beschäftigten berücksich... | FLAG_INCLUDE_SHOULD | +| 2.1.2-S3 | SOLL | R05 | Ein Verfahren zum Umgang mit Verstößen gegen diese Verpflichtungen ist beschrieben. | FLAG_INCLUDE_SHOULD | +| 2.1.3-M1 | MUSS | R05 | Beschäftigte werden geschult und sensibilisiert. | - | +| 2.1.3-S1 | SOLL | R05 | Ein Konzept für Sensibilisierung und Schulung der Beschäftigten ist erstellt. | FLAG_INCLUDE_SHOULD | +| 2.1.3-S2 | SOLL | R05 | Zielgruppen für Schulungs- und Sensibilisierungsmaßnahmen (z. B. Führungskräfte, Administr... | FLAG_INCLUDE_SHOULD | +| 2.1.3-S3 | SOLL | R05 | Das Konzept ist durch die verantwortliche Leitung genehmigt. | FLAG_INCLUDE_SHOULD | +| 2.1.3-S4 | SOLL | R05 | Schulungs- und Sensibilisierungsmaßnahmen werden regelmäßig und anlassbezogen durchgeführt... | FLAG_INCLUDE_SHOULD | +| 2.1.3-S5 | SOLL | R05 | Die Teilnahme an Schulungs- und Sensibilisierungsmaßnahmen wird dokumentiert. | FLAG_INCLUDE_SHOULD | +| 2.1.3-S6 | SOLL | R05 | Ansprechpartner für Informationssicherheit sind den Beschäftigten bekannt. | FLAG_INCLUDE_SHOULD | +| 2.1.4-M1 | MUSS | R06 | Die Anforderungen an mobiles Arbeiten sind bestimmt und erfüllt; dabei werden die einschlä... | - | +| 2.1.4-S1 | SOLL | R06 | Die einschlägigen Aspekte des mobilen Arbeitens werden berücksichtigt. | FLAG_INCLUDE_SHOULD | +| 2.1.4-S2 | SOLL | R06 | Sensibilisierung der Beschäftigten. | FLAG_INCLUDE_SHOULD | +| 2.1.4-H1 | HOCH | R06 | Schutzmaßnahmen gegen Abhören und Einsehen sind umgesetzt. (C) | FLAG_HIGH_PROTECTION | +| 3.1.1-M1 | MUSS | R07 | Ein Sicherheitszonenkonzept einschließlich zugehöriger Schutzmaßnahmen auf Basis der Anfor... | - | +| 3.1.1-M2 | MUSS | R07 | Die definierten Schutzmaßnahmen sind umgesetzt. | - | +| 3.1.1-M3 | MUSS | R07 | Der Verhaltenskodex für Sicherheitszonen ist allen beteiligten Personen bekannt. | - | +| 3.1.1-S1 | SOLL | R07 | Verfahren für die Vergabe und den Entzug von Zutrittsrechten sind etabliert. | FLAG_INCLUDE_SHOULD | +| 3.1.1-S2 | SOLL | R07 | Richtlinien für das Besuchermanagement (einschließlich Registrierung und Begleitung von Be... | FLAG_INCLUDE_SHOULD | +| 3.1.1-S3 | SOLL | R07 | Richtlinien für das Mitführen und Nutzen mobiler IT-Geräte und Datenträger (z. B. Registri... | FLAG_INCLUDE_SHOULD | +| 3.1.1-S4 | SOLL | R07 | Netzwerk-/Infrastrukturkomponenten (eigene oder Kundennetze) sind gegen unbefugten Zugriff... | FLAG_INCLUDE_SHOULD | +| 3.1.1-S5 | SOLL | R07 | Externe Liegenschaften zur Speicherung/Verarbeitung von Informationswerten sind im Zonenko... | FLAG_INCLUDE_SHOULD | +| 3.1.1-H1 | HOCH | R07 | Schutzmaßnahmen gegen einfaches Abhören und Einsehen sind umgesetzt. (C) | FLAG_HIGH_PROTECTION | +| 3.1.4-M1 | MUSS | R06 | Die Anforderungen an mobile IT-Geräte und mobile Datenträger sind bestimmt und erfüllt; da... | - | +| 3.1.4-S1 | SOLL | R06 | Registrierung der IT-Geräte. | FLAG_INCLUDE_SHOULD | +| 3.1.4-H1 | HOCH | R06 | Generelle Verschlüsselung mobiler Datenträger bzw. der darauf gespeicherten Informationswe... | FLAG_HIGH_PROTECTION | +| 4.1.1-M1 | MUSS | R08 | Die Anforderungen an den Umgang mit Identifikationsmitteln über den gesamten Lebenszyklus ... | - | +| 4.1.1-S1 | SOLL | R08 | Identifikationsmittel können nur unter kontrollierten Bedingungen erstellt werden. | FLAG_INCLUDE_SHOULD | +| 4.1.1-H1 | HOCH | R08 | Eine Strategie zur Sperrung oder Ungültigmachung von Identifikationsmitteln im Verlustfall... | FLAG_HIGH_PROTECTION | +| 4.1.2-M1 | MUSS | R08 | Die Verfahren zur Benutzerauthentifizierung sind auf Basis einer Risikobewertung ausgewähl... | - | +| 4.1.2-M2 | MUSS | R08 | Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt. | - | +| 4.1.2-S1 | SOLL | R08 | Die Authentifizierungsverfahren sind auf Basis der geschäftlichen und sicherheitsrelevante... | FLAG_INCLUDE_SHOULD | +| 4.1.2-S2 | SOLL | R08 | Benutzer werden mindestens durch starke Passwörter nach bewährten und anerkannten Praktike... | FLAG_INCLUDE_SHOULD | +| 4.1.2-S3 | SOLL | R08 | Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt (z. B. Privileged A... | FLAG_INCLUDE_SHOULD | +| 4.1.2-H1 | HOCH | R08 | Abhängig von der Risikobewertung sind Authentifizierung und Zugangskontrolle durch ergänze... | FLAG_HIGH_PROTECTION | +| 4.1.2-V1 | SEHR HOCH | R08 | Vor dem Zugriff auf Daten mit sehr hohem Schutzbedarf werden Benutzer mittels starker Auth... | FLAG_VERY_HIGH_PROTECTION | +| 4.1.3-M1 | MUSS | R08 | Das Erstellen, Ändern und Löschen von Benutzerkonten wird durchgeführt. | - | +| 4.1.3-M2 | MUSS | R08 | Eindeutige und personalisierte Benutzerkonten werden verwendet. | - | +| 4.1.3-M3 | MUSS | R08 | Die Nutzung von Sammelkonten ist geregelt (z. B. beschränkt auf Fälle, in denen Nachvollzi... | - | +| 4.1.3-M4 | MUSS | R08 | Benutzerkonten werden unmittelbar nach dem Ausscheiden des Nutzers deaktiviert (z. B. bei ... | - | +| 4.1.3-M5 | MUSS | R08 | Benutzerkonten werden regelmäßig überprüft. | - | +| 4.1.3-M6 | MUSS | R08 | Die Anmeldeinformationen werden dem Nutzer auf sichere Weise bereitgestellt. | - | +| 4.1.3-M7 | MUSS | R08 | Eine Richtlinie zum Umgang mit Anmeldeinformationen ist definiert und umgesetzt; dabei wer... | - | +| 4.1.3-S1 | SOLL | R08 | Ein Basiskonto mit minimalen Zugriffsrechten und Funktionalitäten existiert und wird genut... | FLAG_INCLUDE_SHOULD | +| 4.1.3-S10 | SOLL | R08 | Interaktive Anmeldung für Dienstkonten (technische Konten) wird technisch verhindert. | FLAG_INCLUDE_SHOULD | +| 4.1.3-S2 | SOLL | R08 | Vom Hersteller vorkonfigurierte Standardkonten und -passwörter sind deaktiviert (z. B. Spe... | FLAG_INCLUDE_SHOULD | +| 4.1.3-S3 | SOLL | R08 | Benutzerkonten werden durch die verantwortliche Stelle erstellt oder autorisiert. | FLAG_INCLUDE_SHOULD | +| 4.1.3-S4 | SOLL | R08 | Das Erstellen von Benutzerkonten unterliegt einem Genehmigungsprozess (Vier-Augen-Prinzip)... | FLAG_INCLUDE_SHOULD | +| 4.1.3-S5 | SOLL | R08 | Benutzerkonten von Dienstleistern werden nach Abschluss ihrer Aufgabe deaktiviert. | FLAG_INCLUDE_SHOULD | +| 4.1.3-S6 | SOLL | R08 | Fristen für das Deaktivieren und Löschen von Benutzerkonten sind definiert. | FLAG_INCLUDE_SHOULD | +| 4.1.3-S7 | SOLL | R08 | Die Verwendung von Standardpasswörtern wird technisch verhindert. | FLAG_INCLUDE_SHOULD | +| 4.1.3-S8 | SOLL | R08 | Bei starker Authentifizierung ist die Nutzung des Mediums (z. B. Besitzfaktor) sicher. | FLAG_INCLUDE_SHOULD | +| 4.1.3-S9 | SOLL | R08 | Benutzerkonten werden regelmäßig überprüft; dies umfasst auch Konten in IT-Systemen von Ku... | FLAG_INCLUDE_SHOULD | +| 4.2.1-M1 | MUSS | R08 | Die Anforderungen an die Verwaltung von Zugriffsrechten (Autorisierung) sind bestimmt und ... | - | +| 4.2.1-M2 | MUSS | R08 | Die für normale und privilegierte Benutzerkonten sowie technische Konten vergebenen Zugrif... | - | +| 4.2.1-S1 | SOLL | R08 | Strategien zur Autorisierung von Zugriffen auf Informationen sind vorbereitet. | FLAG_INCLUDE_SHOULD | +| 4.2.1-S2 | SOLL | R08 | Autorisierungsrollen werden verwendet. | FLAG_INCLUDE_SHOULD | +| 4.2.1-S3 | SOLL | R08 | Rechte werden nach dem Need-to-use-Prinzip und gemäß Rolle und/oder Verantwortungsbereich ... | FLAG_INCLUDE_SHOULD | +| 4.2.1-S4 | SOLL | R08 | Normale Benutzerkonten erhalten keine privilegierten Zugriffsrechte. | FLAG_INCLUDE_SHOULD | +| 4.2.1-S5 | SOLL | R08 | Die Zugriffsrechte des Nutzers werden nach Änderung seiner Verantwortlichkeiten aktualisie... | FLAG_INCLUDE_SHOULD | +| 4.2.1-H1 | HOCH | R08 | Die Zugriffsrechte werden durch den verantwortlichen internen Information Officer genehmig... | FLAG_HIGH_PROTECTION | +| 4.2.1-V1 | SEHR HOCH | R08 | Informationen werden auf Inhaltsebene (z. B. Dateiebene) verschlüsselt gespeichert, um unb... | FLAG_VERY_HIGH_PROTECTION | +| 4.2.1-V2 | SEHR HOCH | R08 | Bestehende Zugriffsrechte werden in kürzeren Abständen (z. B. quartalsweise) überprüft. (C... | FLAG_VERY_HIGH_PROTECTION | +| 5.1.1-M1 | MUSS | R09 | Alle eingesetzten kryptografischen Verfahren (z. B. Verschlüsselung, Signatur, Hash-Algori... | - | +| 5.1.1-S1 | SOLL | R09 | Ein Konzept für den Einsatz von Kryptografie ist definiert und umgesetzt; dabei werden die... | FLAG_INCLUDE_SHOULD | +| 5.1.1-H1 | HOCH | R09 | Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) sind bestimm... | FLAG_HIGH_PROTECTION | +| 5.1.2-M1 | MUSS | R09 | Die zur Informationsübertragung genutzten Netzdienste sind identifiziert und dokumentiert. | - | +| 5.1.2-M2 | MUSS | R09 | Richtlinien und Verfahren entsprechend den Klassifizierungsanforderungen für die Nutzung v... | - | +| 5.1.2-M3 | MUSS | R09 | Maßnahmen zum Schutz übertragener Inhalte gegen unbefugten Zugriff sind umgesetzt. | - | +| 5.1.2-S1 | SOLL | R09 | Maßnahmen zur Sicherstellung korrekter Adressierung und korrekter Informationsübertragung ... | FLAG_INCLUDE_SHOULD | +| 5.1.2-S2 | SOLL | R09 | Elektronischer Datenaustausch erfolgt mittels Inhalts- oder Transportverschlüsselung entsp... | FLAG_INCLUDE_SHOULD | +| 5.1.2-S3 | SOLL | R09 | Fernzugriffsverbindungen zum Netzwerk der Organisation verfügen über angemessene Sicherhei... | FLAG_INCLUDE_SHOULD | +| 5.1.2-H1 | HOCH | R09 | Informationen werden verschlüsselt übertragen (mindestens Transportverschlüsselung) oder d... | FLAG_HIGH_PROTECTION | +| 5.1.2-V1 | SEHR HOCH | R09 | Informationen werden inhaltsverschlüsselt übertragen. (C) | FLAG_VERY_HIGH_PROTECTION | +| 5.2.1-M1 | MUSS | R10 | Informationssicherheitsanforderungen für Änderungen an Organisation, Geschäftsprozessen un... | - | +| 5.2.1-S1 | SOLL | R10 | Ein formales Genehmigungsverfahren ist etabliert. | FLAG_INCLUDE_SHOULD | +| 5.2.1-S2 | SOLL | R10 | Die möglichen Auswirkungen von Änderungen auf die Informationssicherheit werden bewertet. | FLAG_INCLUDE_SHOULD | +| 5.2.1-S3 | SOLL | R10 | Änderungen mit Auswirkung auf die Informationssicherheit werden geplant und getestet. | FLAG_INCLUDE_SHOULD | +| 5.2.1-S4 | SOLL | R10 | Verfahren zum Rückfall (Fallback) in Fehlerfällen werden berücksichtigt. | FLAG_INCLUDE_SHOULD | +| 5.2.1-H1 | HOCH | R10 | Die Einhaltung der Informationssicherheitsanforderungen wird während und nach den Änderung... | FLAG_HIGH_PROTECTION | +| 5.2.2-M1 | MUSS | R10 | Die IT-Systeme wurden einer Risikobewertung unterzogen, um die Notwendigkeit ihrer Trennun... | - | +| 5.2.2-M2 | MUSS | R10 | Eine Segmentierung ist auf Basis der Ergebnisse der Risikoanalyse umgesetzt. | - | +| 5.2.2-S1 | SOLL | R10 | Die Anforderungen an Entwicklungs- und Testumgebungen sind bestimmt und erfüllt; dabei wer... | FLAG_INCLUDE_SHOULD | +| 5.2.3-M1 | MUSS | R10 | Anforderungen zum Schutz vor Schadsoftware sind bestimmt. | - | +| 5.2.3-M2 | MUSS | R10 | Technische und organisatorische Maßnahmen zum Schutz vor Schadsoftware sind definiert und ... | - | +| 5.2.3-S1 | SOLL | R10 | Unnötige Netzwerkdienste sind deaktiviert. | FLAG_INCLUDE_SHOULD | +| 5.2.3-S2 | SOLL | R10 | Der Zugriff auf Netzwerkdienste ist durch geeignete Schutzmaßnahmen auf das Notwendige bes... | FLAG_INCLUDE_SHOULD | +| 5.2.3-S3 | SOLL | R10 | Schutzsoftware gegen Schadsoftware ist installiert und wird regelmäßig automatisch aktuali... | FLAG_INCLUDE_SHOULD | +| 5.2.3-S4 | SOLL | R10 | Empfangene Dateien und Software werden vor der Ausführung automatisch auf Schadsoftware ge... | FLAG_INCLUDE_SHOULD | +| 5.2.3-S5 | SOLL | R10 | Der gesamte Datenbestand aller Systeme wird regelmäßig auf Schadsoftware geprüft. | FLAG_INCLUDE_SHOULD | +| 5.2.3-S6 | SOLL | R10 | Über zentrale Gateways übertragene Daten (z. B. E-Mail, Internet, Fremdnetze) werden autom... | FLAG_INCLUDE_SHOULD | +| 5.2.3-S7 | SOLL | R10 | Maßnahmen, die verhindern, dass Schutzsoftware durch Nutzer deaktiviert oder verändert wir... | FLAG_INCLUDE_SHOULD | +| 5.2.3-S8 | SOLL | R10 | Für IT-Systeme ohne Schutzsoftware sind alternative Maßnahmen umgesetzt (z. B. besondere R... | FLAG_INCLUDE_SHOULD | +| 5.2.4-M1 | MUSS | R10 | Informationssicherheitsanforderungen an den Umgang mit Ereignisprotokollen sind bestimmt u... | - | +| 5.2.4-M2 | MUSS | R10 | Sicherheitsrelevante Anforderungen an die Protokollierung von Aktivitäten von Administrato... | - | +| 5.2.4-M3 | MUSS | R10 | Die eingesetzten IT-Systeme werden hinsichtlich der Notwendigkeit der Protokollierung bewe... | - | +| 5.2.4-M4 | MUSS | R10 | Bei Nutzung externer IT-Dienste werden Informationen zu den Überwachungsmöglichkeiten eing... | - | +| 5.2.4-M5 | MUSS | R10 | Ereignisprotokolle werden regelmäßig auf Richtlinienverstöße und auffällige Probleme geprü... | - | +| 5.2.4-S1 | SOLL | R10 | Ein Verfahren zur Eskalation relevanter Ereignisse an die verantwortliche Stelle ist defin... | FLAG_INCLUDE_SHOULD | +| 5.2.4-S2 | SOLL | R10 | Ereignisprotokolle (Inhalt und Metadaten) sind gegen Veränderung geschützt (z. B. durch ei... | FLAG_INCLUDE_SHOULD | +| 5.2.4-S3 | SOLL | R10 | Eine angemessene Überwachung und Aufzeichnung aller informationssicherheitsrelevanten Akti... | FLAG_INCLUDE_SHOULD | +| 5.2.4-H1 | HOCH | R10 | Sicherheitsrelevante Anforderungen an den Umgang mit Ereignisprotokollen, z. B. vertraglic... | FLAG_HIGH_PROTECTION | +| 5.2.4-H2 | HOCH | R10 | Ereignisse zu Auf- und Abbau von Fernzugriffssitzungen (z. B. Fernwartung) werden protokol... | FLAG_HIGH_PROTECTION | +| 5.2.4-V1 | SEHR HOCH | R10 | Protokollierung jedes Zugriffs auf Daten mit sehr hohem Schutzbedarf, soweit technisch mac... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.5-M1 | MUSS | R10 | Informationen über technische Schwachstellen der eingesetzten IT-Systeme werden erhoben (z... | - | +| 5.2.5-M2 | MUSS | R10 | Potenziell betroffene IT-Systeme und Software werden identifiziert und das durch die Schwa... | - | +| 5.2.5-M3 | MUSS | R10 | Risiken aus Schwachstellen werden behandelt. | - | +| 5.2.5-S1 | SOLL | R10 | Ein angemessenes Patch-Management ist definiert und umgesetzt (z. B. Patch-Test und -Insta... | FLAG_INCLUDE_SHOULD | +| 5.2.5-S2 | SOLL | R10 | Risikominimierende Maßnahmen werden bei Bedarf umgesetzt. | FLAG_INCLUDE_SHOULD | +| 5.2.5-S3 | SOLL | R10 | Die erfolgreiche Installation von Patches wird in geeigneter Weise verifiziert. | FLAG_INCLUDE_SHOULD | +| 5.2.6-M1 | MUSS | R10 | Anforderungen an die Prüfung (Audit) von IT-Systemen oder -Diensten sind bestimmt. | - | +| 5.2.6-M2 | MUSS | R10 | Der Umfang der Systemprüfung wird rechtzeitig festgelegt. | - | +| 5.2.6-M3 | MUSS | R10 | System- oder Dienstprüfungen werden mit Betreiber und Nutzern der IT-Systeme/-Dienste abge... | - | +| 5.2.6-M4 | MUSS | R10 | Die Ergebnisse von System-/Dienstprüfungen werden nachvollziehbar gespeichert und der zust... | - | +| 5.2.6-M5 | MUSS | R10 | Aus den Ergebnissen werden Maßnahmen abgeleitet und in angemessener Frist umgesetzt. | - | +| 5.2.6-S1 | SOLL | R10 | System- und Dienstprüfungen werden unter Berücksichtigung möglicher Sicherheitsrisiken (z.... | FLAG_INCLUDE_SHOULD | +| 5.2.6-S2 | SOLL | R10 | Regelmäßige System- oder Dienstprüfungen werden durchgeführt; dabei werden die einschlägig... | FLAG_INCLUDE_SHOULD | +| 5.2.6-S3 | SOLL | R10 | Innerhalb einer angemessenen Frist nach Abschluss der Prüfung wird ein Bericht erstellt. | FLAG_INCLUDE_SHOULD | +| 5.2.6-H1 | HOCH | R10 | Für kritische IT-Systeme/-Dienste wurden zusätzliche Prüfanforderungen identifiziert und w... | FLAG_HIGH_PROTECTION | +| 5.2.6-V1 | SEHR HOCH | R10 | IT-Systeme und -Dienste werden regelmäßig auf Schwachstellen gescannt. Für nicht scanbare ... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.7-M1 | MUSS | R10 | Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und erfüllt... | - | +| 5.2.7-M2 | MUSS | R10 | Anforderungen an die Netzsegmentierung sind bestimmt und erfüllt. | - | +| 5.2.7-S1 | SOLL | R10 | Verfahren für das Management und die Steuerung von Netzwerken sind definiert. | FLAG_INCLUDE_SHOULD | +| 5.2.7-S2 | SOLL | R10 | Für eine risikobasierte Netzsegmentierung werden die einschlägigen Aspekte berücksichtigt. | FLAG_INCLUDE_SHOULD | +| 5.2.7-H1 | HOCH | R10 | Erweiterte Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt ... | FLAG_HIGH_PROTECTION | +| 5.2.8-M1 | MUSS | R04 | Kritische IT-Dienste sind identifiziert und die Geschäftsauswirkung wird berücksichtigt. | - | +| 5.2.8-M2 | MUSS | R04 | Anforderungen und Verantwortlichkeiten für Kontinuität und Wiederherstellung dieser IT-Die... | - | +| 5.2.8-S1 | SOLL | R04 | Kritische IT-Systeme sind identifiziert; dabei werden die einschlägigen Aspekte berücksich... | FLAG_INCLUDE_SHOULD | +| 5.2.8-S2 | SOLL | R04 | Eine Kontinuitätsplanung existiert und wird regelmäßig überprüft und aktualisiert. | FLAG_INCLUDE_SHOULD | +| 5.2.8-S3 | SOLL | R04 | Die Kontinuitätsplanung umfasst mindestens (D)DoS-Angriffe, erfolgreiche Ransomware-Angrif... | FLAG_INCLUDE_SHOULD | +| 5.2.8-H1 | HOCH | R04 | Die Kontinuitätsplanung enthält vordefinierte Zeitrahmen (Recovery Time Objective) für die... | FLAG_HIGH_PROTECTION | +| 5.2.8-H2 | HOCH | R04 | Angemessene SLAs mit externen Dienstleistern entsprechend der Kontinuitätsplanung bestehen... | FLAG_HIGH_PROTECTION | +| 5.2.8-H3 | HOCH | R04 | Die Kontinuitätspläne umfassen die Koordination vertraglich vereinbarter Kommunikation mit... | FLAG_HIGH_PROTECTION | +| 5.2.8-H4 | HOCH | R04 | Die Kontinuitätsplanung wird regelmäßig getestet, inkl. vollständiger Wiederherstellung in... | FLAG_HIGH_PROTECTION | +| 5.2.8-H5 | HOCH | R04 | Eine Backup- und Wiederherstellungsstrategie für kritische IT-Dienste und Informationen is... | FLAG_HIGH_PROTECTION | +| 5.2.8-H6 | HOCH | R04 | Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugte Veränderu... | FLAG_HIGH_PROTECTION | +| 5.2.8-H7 | HOCH | R04 | Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugten Zugriff ... | FLAG_HIGH_PROTECTION | +| 5.2.8-V1 | SEHR HOCH | R04 | Die Kontinuitätsplanung ist mit den Kontinuitätsplänen relevanter externer Dienstleister a... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.8-V2 | SEHR HOCH | R04 | Die Fortführung wesentlicher Kern- und Geschäftsfunktionen mit minimalem oder keinem Verlu... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.8-V3 | SEHR HOCH | R04 | Die Kontinuitätsplanung wird regelmäßig getestet. Testszenarien, Ergebnisse und Lessons Le... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.9-M1 | MUSS | R10 | Backup-Konzepte existieren für relevante IT-Systeme. Angemessene Schutzmaßnahmen für Vertr... | - | +| 5.2.9-M2 | MUSS | R10 | Wiederherstellungskonzepte existieren für relevante IT-Dienste. | - | +| 5.2.9-S1 | SOLL | R10 | Für jeden relevanten IT-Dienst existiert ein Backup- und Wiederherstellungskonzept. Abhäng... | FLAG_INCLUDE_SHOULD | +| 5.2.9-H1 | HOCH | R10 | Backup- und Wiederherstellungskonzepte werden methodisch in regelmäßigen Abständen überprü... | FLAG_HIGH_PROTECTION | +| 5.2.9-H2 | HOCH | R10 | Die grundsätzliche Wiederherstellbarkeit wird berücksichtigt und getestet (z. B. Stichprob... | FLAG_HIGH_PROTECTION | +| 5.2.9-V1 | SEHR HOCH | R10 | (Zusätzliche) Backups werden über Offline-Verfahren, unveränderliche (immutable) Backups o... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.9-V2 | SEHR HOCH | R10 | Wiederherstellungsverfahren werden methodisch in regelmäßigen Abständen technisch getestet... | FLAG_VERY_HIGH_PROTECTION | +| 5.2.9-V3 | SEHR HOCH | R10 | Geografische Redundanz wird in Backup- und Wiederherstellungskonzepten berücksichtigt. (A) | FLAG_VERY_HIGH_PROTECTION | +| 5.3.1-M1 | MUSS | R11 | Die mit Design und Entwicklung eines IT-Dienstes verbundenen Informationssicherheitsanford... | - | +| 5.3.1-M2 | MUSS | R11 | Die mit Beschaffung oder Erweiterung von IT-Diensten und -Komponenten verbundenen Informat... | - | +| 5.3.1-M3 | MUSS | R11 | Informationssicherheitsanforderungen im Zusammenhang mit Änderungen an entwickelten IT-Die... | - | +| 5.3.1-M4 | MUSS | R11 | Systemabnahmetests werden unter Berücksichtigung der Informationssicherheitsanforderungen ... | - | +| 5.3.1-S1 | SOLL | R11 | Anforderungsspezifikationen werden erstellt; dabei werden die einschlägigen Aspekte berück... | FLAG_INCLUDE_SHOULD | +| 5.3.1-S2 | SOLL | R11 | Anforderungsspezifikationen werden gegen die Informationssicherheitsanforderungen geprüft. | FLAG_INCLUDE_SHOULD | +| 5.3.1-S3 | SOLL | R11 | Der IT-Dienst wird vor Produktivnutzung auf Einhaltung der Spezifikationen geprüft. | FLAG_INCLUDE_SHOULD | +| 5.3.1-S4 | SOLL | R11 | Die Nutzung von Produktivdaten zu Testzwecken wird soweit möglich vermieden (ggf. Anonymis... | FLAG_INCLUDE_SHOULD | +| 5.3.1-S5 | SOLL | R11 | Testsysteme erhalten Schutzmaßnahmen vergleichbar zur Produktivumgebung, wenn Produktivdat... | FLAG_INCLUDE_SHOULD | +| 5.3.1-V1 | SEHR HOCH | R11 | Die Sicherheit zweckgebauter oder wesentlich angepasster Software wird bei Inbetriebnahme,... | FLAG_VERY_HIGH_PROTECTION | +| 5.3.2-M1 | MUSS | R11 | Anforderungen an die Informationssicherheit von Netzdiensten sind bestimmt und erfüllt. | - | +| 5.3.2-S1 | SOLL | R11 | Ein Verfahren zur Absicherung und Nutzung von Netzdiensten ist definiert und umgesetzt. | FLAG_INCLUDE_SHOULD | +| 5.3.2-S2 | SOLL | R11 | Die Anforderungen werden in Form von SLAs vereinbart. | FLAG_INCLUDE_SHOULD | +| 5.3.2-S3 | SOLL | R11 | Angemessene Redundanzlösungen sind umgesetzt. | FLAG_INCLUDE_SHOULD | +| 5.3.2-H1 | HOCH | R11 | Verfahren zur Überwachung der Qualität des Netzverkehrs (z. B. Traffic-Flow-Analysen, Verf... | FLAG_HIGH_PROTECTION | +| 5.3.3-S1 | SOLL | R11 | Eine Beschreibung des Beendigungsprozesses ist vorhanden, an Änderungen angepasst und vert... | FLAG_INCLUDE_SHOULD | +| 5.3.4-M1 | MUSS | R12 | Eine wirksame Trennung (z. B. Mandantentrennung) verhindert den Zugriff unbefugter Nutzer ... | - | +| 5.3.4-S1 | SOLL | R12 | Das Trennungskonzept des Anbieters ist dokumentiert und an Änderungen angepasst; dabei wer... | FLAG_INCLUDE_SHOULD | +| 5.3.4-KI-M1 | MUSS | R12 | Der Einsatz von KI-/GenAI-Diensten ist geregelt; es werden nur freigegebene Dienste genutz... | - | +| 5.3.4-KI-M2 | MUSS | R12 | Die Eingabe vertraulicher oder personenbezogener Informationen in nicht freigegebene KI-Di... | - | +| 5.3.4-KI-M3 | MUSS | R12 | Bei freigegebenen KI-Diensten ist geklärt und vertraglich sichergestellt, dass Eingaben ni... | - | +| 5.3.4-KI-S1 | SOLL | R12 | Ergebnisse von KI-Diensten werden vor geschäftskritischer Verwendung geprüft (Human-in-the... | FLAG_INCLUDE_SHOULD | +| 6.1.1-M1 | MUSS | R13 | Auftragnehmer und Partner werden einer Sicherheitsrisikobewertung unterzogen. | - | +| 6.1.1-M2 | MUSS | R13 | Ein angemessenes Informationssicherheitsniveau wird durch vertragliche Vereinbarungen mit ... | - | +| 6.1.1-M3 | MUSS | R13 | Sofern zutreffend, werden vertragliche Vereinbarungen mit Auftraggebern/Kunden an Auftragn... | - | +| 6.1.1-S1 | SOLL | R13 | Auftragnehmer und Partner sind vertraglich verpflichtet, Anforderungen an ein angemessenes... | FLAG_INCLUDE_SHOULD | +| 6.1.1-S2 | SOLL | R13 | Leistungsberichte und Dokumente von Auftragnehmern und Partnern werden geprüft. | FLAG_INCLUDE_SHOULD | +| 6.1.1-H1 | HOCH | R13 | Es wird nachgewiesen, dass das Informationssicherheitsniveau des Lieferanten dem Schutzbed... | FLAG_HIGH_PROTECTION | +| 6.1.1-H2 | HOCH | R13 | Der Grad der Erfüllung geforderter Nachweise durch den Lieferanten wird dokumentiert, rege... | FLAG_HIGH_PROTECTION | +| 6.1.1-H3 | HOCH | R13 | Die Einhaltung vertraglicher Vereinbarungen durch den Lieferanten wird geprüft, dokumentie... | FLAG_HIGH_PROTECTION | +| 6.1.1-V1 | SEHR HOCH | R13 | Das angemessene Informationssicherheitsniveau sollte durch ein Drittparteien-Audit (angeme... | FLAG_VERY_HIGH_PROTECTION | +| 6.1.1-V2 | SEHR HOCH | R13 | Vertragliche Verpflichtungen gegenüber Kunden zur Transparenz von Lieferkettenrisiken werd... | FLAG_VERY_HIGH_PROTECTION | +| 6.1.2-M1 | MUSS | R13 | Die Vertraulichkeitsanforderungen sind bestimmt und erfüllt. | - | +| 6.1.2-M2 | MUSS | R13 | Anforderungen und Verfahren zur Anwendung von Vertraulichkeitsvereinbarungen sind allen Pe... | - | +| 6.1.2-M3 | MUSS | R13 | Gültige Vertraulichkeitsvereinbarungen werden vor der Weitergabe schutzbedürftiger Informa... | - | +| 6.1.2-M4 | MUSS | R13 | Die Anforderungen und Verfahren zur Nutzung von Vertraulichkeitsvereinbarungen und zum Umg... | - | +| 6.1.2-S1 | SOLL | R13 | Vorlagen für Vertraulichkeitsvereinbarungen sind vorhanden und auf rechtliche Anwendbarkei... | FLAG_INCLUDE_SHOULD | +| 6.1.2-S2 | SOLL | R13 | Vertraulichkeitsvereinbarungen umfassen beteiligte Personen/Organisationen, Art der Inform... | FLAG_INCLUDE_SHOULD | +| 6.1.2-S3 | SOLL | R13 | Vertraulichkeitsvereinbarungen enthalten Regelungen zum Umgang mit schutzbedürftigen Infor... | FLAG_INCLUDE_SHOULD | +| 6.1.2-S4 | SOLL | R13 | Möglichkeiten zum Nachweis der Einhaltung (z. B. Prüfung durch unabhängige Dritte oder Aud... | FLAG_INCLUDE_SHOULD | +| 6.1.2-S5 | SOLL | R13 | Ein Prozess zur Überwachung der Gültigkeitsdauer temporärer Vertraulichkeitsvereinbarungen... | FLAG_INCLUDE_SHOULD | +| 6.1.3-M1 | MUSS | R13 | Die betroffenen IT-Dienste sind identifiziert. | - | +| 6.1.3-M2 | MUSS | R13 | Die für den IT-Dienst relevanten Sicherheitsanforderungen sind bestimmt. | - | +| 6.1.3-M3 | MUSS | R13 | Die für die Umsetzung der Anforderung verantwortliche Organisation ist definiert und sich ... | - | +| 6.1.3-M4 | MUSS | R13 | Mechanismen für geteilte Verantwortlichkeiten sind spezifiziert und umgesetzt. | - | +| 6.1.3-M5 | MUSS | R13 | Die verantwortliche Organisation erfüllt ihre jeweiligen Verantwortlichkeiten. | - | +| 6.1.3-S1 | SOLL | R13 | Bei IT-Diensten ist die Konfiguration auf Basis der notwendigen Sicherheitsanforderungen k... | FLAG_INCLUDE_SHOULD | +| 6.1.3-S2 | SOLL | R13 | Das verantwortliche Personal ist angemessen geschult. | FLAG_INCLUDE_SHOULD | +| 6.1.3-H1 | HOCH | R13 | Eine Liste der betroffenen IT-Dienste und der jeweils verantwortlichen IT-Dienstleister ex... | FLAG_HIGH_PROTECTION | +| 6.1.3-H2 | HOCH | R13 | Die Anwendbarkeit der ISA-Controls wurde bewertet und dokumentiert. (C, I, A) | FLAG_HIGH_PROTECTION | +| 6.1.3-H3 | HOCH | R13 | Die Dienstkonfiguration ist in die regelmäßigen Sicherheitsbewertungen einbezogen. (C, I, ... | FLAG_HIGH_PROTECTION | +| 6.1.3-H4 | HOCH | R13 | Es wird nachgewiesen, dass die IT-Dienstleister ihre Verantwortung erfüllen. (C, I, A) | FLAG_HIGH_PROTECTION | +| 6.1.3-H5 | HOCH | R13 | Die Integration in lokale Schutzmaßnahmen (z. B. sichere Authentifizierungsmechanismen) is... | FLAG_HIGH_PROTECTION | +| 7.1.1-M1 | MUSS | R14 | Rechtliche, regulatorische und vertragliche Vorgaben mit Relevanz für die Informationssich... | - | +| 7.1.1-M2 | MUSS | R14 | Richtlinien zur Einhaltung der Vorgaben sind definiert, umgesetzt und den verantwortlichen... | - | +| 7.1.1-S1 | SOLL | R14 | Die Integrität von Aufzeichnungen entsprechend rechtlichen, regulatorischen und vertraglic... | FLAG_INCLUDE_SHOULD | +| 7.1.2-M1 | MUSS | R14 | Rechtliche und vertragliche Informationssicherheitsanforderungen an Verfahren und Prozesse... | - | +| 7.1.2-M2 | MUSS | R14 | Regelungen zur Einhaltung rechtlicher und vertraglicher Anforderungen an den Schutz person... | - | +| 7.1.2-M3 | MUSS | R14 | Prozesse und Verfahren zum Schutz personenbezogener Daten sind im Informationssicherheits-... | - | +## Hinweis zu ISA-Quelldubletten + +Die ISA 2027 enthält im Quelltext **4 doppelte HOCH-Zeilen** (1.6.3 dreifach, 5.2.9 einfach), die inhaltlich identisch mit bereits enthaltenen Anforderungen sind (z. B. Krisenszenarien/-ressourcen/-tests mit und ohne Zusatz „The following aspects are considered"). Diese wurden **konsolidiert**, nicht dupliziert: 316 eindeutige ISA-Zeilen ergeben **312 eindeutige Anforderungen** bei 100 % inhaltlicher Abdeckung. Details siehe `mapping.json` → `meta.isa_quelldubletten`. diff --git a/seed/isms-vorlagenpaket-v2/Nachweisregister_zentral.md b/seed/isms-vorlagenpaket-v2/Nachweisregister_zentral.md new file mode 100644 index 0000000..7846a57 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/Nachweisregister_zentral.md @@ -0,0 +1,47 @@ +# Zentrales Nachweisregister – ISMS {{ORG_NAME}} + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Nachweisregister (gilt für alle Richtlinien) | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | +| Verantwortlich | {{ROLE_ISB}} | + +## Zweck + +Dieses Dokument bündelt **alle Nachweise** für das ISMS an einer Stelle. Die einzelnen Richtlinien enthalten keine Nachweislisten, sondern verweisen hierauf ({{LINK:NACHWEISREGISTER}}). Register mit laufenden Datensätzen (Asset-Inventar, Risikoregister, Lieferanten-/NDA-Verzeichnis, Awareness-Nachweise, Verzeichnis der Verarbeitungstätigkeiten) werden in **{{TOOL_NAME}}** gepflegt; dieses Register verweist darauf. + +Die feingranulare Zuordnung Nachweis ↔ einzelne MUSS/SOLL-Anforderung erfolgt über `mapping.json` (Hidden-Anker `REQ`/`IMPL`) und ist im Lesemodus nicht sichtbar. Das Tool erzeugt daraus je Anforderung einen Nachweis-Link. + +## Nachweisübersicht + +| # | Richtlinie | Nachweis | Quelle | Verantwortlich | Turnus | +|---|-----------|----------|--------|----------------|--------| +| 1 | {{LINK:L00}} | Freigegebene, versionierte IS-Leitlinie inkl. Kommunikationsbeleg | Dok | {{ROLE_MANAGEMENT}} | {{REVIEW_CYCLE}} | +| 2 | {{LINK:R01}} | ISMS-Scope, Rollen-/Verantwortungsmatrix, Managementbewertung | Tool/Dok | {{ROLE_ISB}} | jährlich | +| 3 | {{LINK:R02}} | Asset-Inventar & Klassifizierungsmatrix; Liste zugelassener Hard-/Software | Tool | {{ROLE_IT_LEAD}} | laufend | +| 4 | {{LINK:R03}} | Risikoregister & Behandlungsplan; interne/unabhängige Prüfberichte | Tool/Dok | {{ROLE_ISB}} | ≤ jährlich | +| 5 | {{LINK:R04}} | Incident-Aufzeichnungen; Krisen-/Notfallplan; Wiederanlauftests | Tool/Dok | {{ROLE_ISB}} | laufend | +| 6 | {{LINK:R05}} | Vertraulichkeitsverpflichtungen; Schulungs-/Awareness-Nachweise | Tool | {{ROLE_HR_LEAD}} | bei Eintritt / jährlich | +| 7 | {{LINK:R06}} | Regelung & Genehmigungen mobiles Arbeiten / mobile Geräte | Dok/Tool | {{ROLE_ISB}} | laufend | +| 8 | {{LINK:R07}} | Zutrittskonzept, Zonenplan, Zutrittsprotokolle | Dok | {{ROLE_IT_LEAD}} | laufend | +| 9 | {{LINK:R08}} | Berechtigungskonzept & Rezertifizierungsnachweise | Tool | {{ROLE_IT_LEAD}} | ≤ jährlich | +| 10 | {{LINK:R09}} | Kryptokonzept, Schlüssel-/Zertifikatsverwaltung | Dok | {{ROLE_IT_LEAD}} | laufend | +| 11 | {{LINK:R10}} | Change-/Patch-/Schwachstellenberichte, Malware-Status, Logging, Backup-/Recovery-Tests | Tool/Aufz. | {{ROLE_IT_LEAD}} | laufend | +| 12 | {{LINK:R11}} | Sicherheitsanforderungen Beschaffung/Entwicklung; Löschnachweise | Dok/Aufz. | {{ROLE_IT_LEAD}} | laufend | +| 13 | {{LINK:R12}} | Freigabeliste Cloud-/KI-Dienste, Segregations-/Datenflussnachweise | Tool/Dok | {{ROLE_ISB}} | laufend | +| 14 | {{LINK:R13}} | Lieferantenverzeichnis, NDAs, Verantwortungsabgrenzung | Tool | {{ROLE_ISB}} | laufend | +| 15 | {{LINK:R14}} | Compliance-/Rechtsregister; Verzeichnis der Verarbeitungstätigkeiten | Tool | {{ROLE_DPO}} | ≤ jährlich | +| 16 | {{LINK:VA-22}} | Kennzahlenblatt mit Zielwerten, Verantwortlichen und Messwerten je Periode | Tool | {{ROLE_ISB}} | {{MGMT_REVIEW_CYCLE}} | +| 17 | {{LINK:VA-22}} | Protokoll der Managementbewertung mit Eingaben, Beschlüssen und Terminen | Tool/Dok | {{ROLE_MANAGEMENT}} | {{MGMT_REVIEW_CYCLE}} | +| 18 | {{LINK:VA-21}} | Maßnahmenregister: Nichtkonformitäten, Ursachenanalyse, Wirksamkeitsbewertung | Tool | {{ROLE_ISB}} | laufend | +| 19 | {{LINK:R03}} | Erklärung zur Anwendbarkeit (SoA) mit Begründung, Herkunft und Umsetzungsstatus | Tool/Dok | {{ROLE_ISB}} | {{RISK_REVIEW_CYCLE}} | +| 20 | {{LINK:L00}} | Lesebestätigungen der Beschäftigten je freigegebener Richtlinienfassung | Tool | {{ROLE_ISB}} | {{POLICY_REVIEW_CYCLE}} | + +> **Wizard-Hinweis:** Zeilen mit Quelle `Tool` werden nicht als Dokument erzeugt, sondern verlinken auf den Datensatz im {{TOOL_NAME}}. Bedingte Nachweise werden anhand der Feature-Flags ein-/ausgeblendet (z. B. Zeile 13 nur bei Flag `FLAG_CLOUD_USED` / `FLAG_AI_USED`, Zeile 10 nur bei Flag `FLAG_CRYPTO_PKI`). + +## Verwandte Dokumente + +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Informationssicherheitsleitlinie: {{LINK:L00}} diff --git a/seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md b/seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md new file mode 100644 index 0000000..3ab1000 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md @@ -0,0 +1,135 @@ +# Erklaerung zur Anwendbarkeit (Statement of Applicability) + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Erklaerung zur Anwendbarkeit (Statement of Applicability) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + +## Zweck + +Diese Erklaerung weist je Massnahme aus Anhang A der ISO/IEC 27001:2022 aus, ob sie anwendbar ist, warum sie einbezogen oder ausgeschlossen wurde, woraus sie sich ergibt und wie weit sie umgesetzt ist (ISO/IEC 27001:2022, 6.1.3 d). Sie wird bei jeder Risikobeurteilung ({{RISK_REVIEW_CYCLE}}) aktualisiert und von {{ROLE_MANAGEMENT}} freigegeben. Das Verfahren ist in {{LINK:R03}} geregelt. + +**Spalten:** *Anwendbar* = ja/nein · *Begruendung* = Grund der Einbeziehung bzw. des Ausschlusses · *Herkunft* = Risiko-ID, gesetzliche oder vertragliche Anforderung · *Status* = umgesetzt / teilweise / geplant · *Nachweis* = Verweis in das Nachweisregister ({{LINK:NACHWEISREGISTER}}). + +## A.5 Organisatorische Massnahmen (37 Massnahmen) + +| Control | Titel | Anwendbar | Begruendung | Herkunft | Status | Richtlinie | Verfahren | Nachweis | +|---|---|:--:|---|---|---|---|---|---| +| A.5.1 | Informationssicherheitsrichtlinien | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:L00}} | - | | +| A.5.2 | Rollen und Verantwortlichkeiten | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R01}} | - | | +| A.5.3 | Aufgabentrennung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R01}} | - | | +| A.5.4 | Verantwortung der Leitung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R01}} | - | | +| A.5.5 | Kontakt mit Behörden | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R01}} | - | | +| A.5.6 | Kontakt mit speziellen Interessengruppen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R01}} | - | | +| A.5.7 | Bedrohungsinformationen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.5.8 | Informationssicherheit im Projektmanagement | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R01}} | VA-19 | | +| A.5.9 | Inventar der Informationen und Assets | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R02}} | VA-08 | | +| A.5.10 | Zulässige Nutzung von Informationen und Assets | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R02}} | VA-08 | | +| A.5.11 | Rückgabe von Assets | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R11}} | VA-08 | | +| A.5.12 | Klassifizierung von Informationen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R02}} | VA-08 | | +| A.5.13 | Kennzeichnung von Informationen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R02}} | VA-08 | | +| A.5.14 | Informationsübertragung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R09}} | - | | +| A.5.15 | Zugangssteuerung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.5.16 | Identitätsmanagement | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.5.17 | Authentisierungsinformationen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.5.18 | Zugriffsrechte | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.5.19 | Informationssicherheit in Lieferantenbeziehungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R13}} | VA-10 | | +| A.5.20 | Informationssicherheit in Lieferantenvereinbarungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R13}} | VA-10 | | +| A.5.21 | Informationssicherheit in der IKT-Lieferkette | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R13}} | VA-10 | | +| A.5.22 | Überwachung und Änderung von Lieferantenleistungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R13}} | VA-10 | | +| A.5.23 | Informationssicherheit bei Cloud-Diensten | {{#if FLAG_CLOUD_USED}}ja{{/if}}{{#unless FLAG_CLOUD_USED}}nein{{/unless}} | {{#if FLAG_CLOUD_USED}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_CLOUD_USED}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R12}} | VA-11 | | +| A.5.24 | Incident-Management: Planung und Vorbereitung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-01 | | +| A.5.25 | Bewertung und Entscheidung zu Ereignissen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-01 | | +| A.5.26 | Reaktion auf Informationssicherheitsvorfälle | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-01 | | +| A.5.27 | Lernen aus Informationssicherheitsvorfällen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-01 | | +| A.5.28 | Sammeln von Beweismaterial | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-01 | | +| A.5.29 | Informationssicherheit während einer Störung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-02 | | +| A.5.30 | IKT-Bereitschaft für Business Continuity | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-02 | | +| A.5.31 | Rechtliche und vertragliche Anforderungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R14}} | VA-18 | | +| A.5.32 | Geistige Eigentumsrechte | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R14}} | VA-18 | | +| A.5.33 | Schutz von Aufzeichnungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R14}} | VA-18 | | +| A.5.34 | Datenschutz und Schutz von PII | {{#if FLAG_PERSONAL_DATA}}ja{{/if}}{{#unless FLAG_PERSONAL_DATA}}nein{{/unless}} | {{#if FLAG_PERSONAL_DATA}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_PERSONAL_DATA}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R14}} | VA-18 | | +| A.5.35 | Unabhängige Überprüfung der Informationssicherheit | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R03}} | VA-15 | | +| A.5.36 | Einhaltung von Richtlinien und Standards | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R03}} | VA-15 | | +| A.5.37 | Dokumentierte Betriebsabläufe | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | + +## A.6 Personenbezogene Massnahmen (8 Massnahmen) + +| Control | Titel | Anwendbar | Begruendung | Herkunft | Status | Richtlinie | Verfahren | Nachweis | +|---|---|:--:|---|---|---|---|---|---| +| A.6.1 | Überprüfung (Screening) | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R05}} | VA-14 | | +| A.6.2 | Arbeitsvertragliche Regelungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R05}} | VA-14 | | +| A.6.3 | Awareness, Ausbildung und Schulung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R05}} | VA-12 | | +| A.6.4 | Disziplinarverfahren | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R05}} | - | | +| A.6.5 | Verantwortlichkeiten nach Beendigung oder Wechsel | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R05}} | VA-14 | | +| A.6.6 | Vertraulichkeitsvereinbarungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R05}} | VA-14 | | +| A.6.7 | Remote-Arbeit | {{#if FLAG_MOBILE_WORK}}ja{{/if}}{{#unless FLAG_MOBILE_WORK}}nein{{/unless}} | {{#if FLAG_MOBILE_WORK}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_MOBILE_WORK}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R06}} | - | | +| A.6.8 | Meldung von Informationssicherheitsereignissen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-01 | | + +## A.7 Physische Massnahmen (14 Massnahmen) + +| Control | Titel | Anwendbar | Begruendung | Herkunft | Status | Richtlinie | Verfahren | Nachweis | +|---|---|:--:|---|---|---|---|---|---| +| A.7.1 | Physische Sicherheitsperimeter | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.2 | Physische Zutrittssteuerung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.3 | Sicherung von Büros, Räumen und Einrichtungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.4 | Physische Überwachung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.5 | Schutz vor physischen und umweltbedingten Bedrohungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.6 | Arbeiten in Sicherheitsbereichen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.7 | Aufgeräumter Arbeitsplatz und Bildschirm | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.8 | Platzierung und Schutz von Betriebsmitteln | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.9 | Sicherheit von Assets außerhalb des Geländes | {{#if FLAG_MOBILE_DEVICES}}ja{{/if}}{{#unless FLAG_MOBILE_DEVICES}}nein{{/unless}} | {{#if FLAG_MOBILE_DEVICES}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_MOBILE_DEVICES}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R06}} | - | | +| A.7.10 | Speichermedien | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R06}} | VA-08 | | +| A.7.11 | Versorgungseinrichtungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.12 | Verkabelungssicherheit | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-17 | | +| A.7.13 | Wartung von Betriebsmitteln | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R07}} | VA-04 | | +| A.7.14 | Sichere Entsorgung oder Wiederverwendung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R11}} | VA-08 | | + +## A.8 Technologische Massnahmen (34 Massnahmen) + +| Control | Titel | Anwendbar | Begruendung | Herkunft | Status | Richtlinie | Verfahren | Nachweis | +|---|---|:--:|---|---|---|---|---|---| +| A.8.1 | Endgeräte der Benutzer | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R06}} | - | | +| A.8.2 | Privilegierte Zugriffsrechte | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.8.3 | Einschränkung des Informationszugriffs | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.8.4 | Zugriff auf Quellcode | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.5 | Sichere Authentisierung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.8.6 | Kapazitätssteuerung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.8.7 | Schutz vor Malware | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.8.8 | Management technischer Schwachstellen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-06 | | +| A.8.9 | Konfigurationsmanagement | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-04 | | +| A.8.10 | Löschung von Informationen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R11}} | VA-08 | | +| A.8.11 | Datenmaskierung | {{#if FLAG_PERSONAL_DATA}}ja{{/if}}{{#unless FLAG_PERSONAL_DATA}}nein{{/unless}} | {{#if FLAG_PERSONAL_DATA}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_PERSONAL_DATA}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R02}} | - | | +| A.8.12 | Verhinderung von Datenlecks | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.8.13 | Informationssicherung (Backup) | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-05 | | +| A.8.14 | Redundanz der Verarbeitungseinrichtungen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R04}} | VA-02 | | +| A.8.15 | Protokollierung (Logging) | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-13 | | +| A.8.16 | Überwachungsaktivitäten | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-13 | | +| A.8.17 | Uhrzeitsynchronisation | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-13 | | +| A.8.18 | Nutzung privilegierter Hilfsprogramme | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R08}} | VA-03 | | +| A.8.19 | Softwareinstallation auf Produktivsystemen | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R02}} | VA-04 | | +| A.8.20 | Netzwerksicherheit | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.8.21 | Sicherheit von Netzwerkdiensten | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R11}} | - | | +| A.8.22 | Netzwerksegmentierung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.8.23 | Web-Filterung | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | - | | +| A.8.24 | Nutzung von Kryptographie | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R09}} | VA-07 | | +| A.8.25 | Sicherer Entwicklungslebenszyklus | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.26 | Sicherheitsanforderungen an Anwendungen | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.27 | Sichere Systemarchitektur und -prinzipien | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.28 | Sichere Programmierung | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.29 | Sicherheitstests in Entwicklung und Abnahme | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.30 | Ausgelagerte Entwicklung | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.31 | Trennung von Entwicklungs-, Test- und Produktionsumgebungen | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R10}} | VA-16 | | +| A.8.32 | Änderungsmanagement | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-04 | | +| A.8.33 | Testinformationen | {{#if FLAG_DEV_INHOUSE}}ja{{/if}}{{#unless FLAG_DEV_INHOUSE}}nein{{/unless}} | {{#if FLAG_DEV_INHOUSE}}Aus der Risikobehandlung als erforderlich bestimmt.{{/if}}{{#unless FLAG_DEV_INHOUSE}}Nicht anwendbar - Begruendung eintragen.{{/unless}} | | | {{LINK:R11}} | VA-16 | | +| A.8.34 | Schutz von Systemen bei Audit-Tests | ja | Aus der Risikobehandlung als erforderlich bestimmt. | | | {{LINK:R10}} | VA-15 | | + +## Managementsystem-Anforderungen (Kap. 4-10) + +Die Anforderungen der Kapitel 4 bis 10 sind nicht Gegenstand der Anwendbarkeitserklaerung; sie gelten unmittelbar. Ihre Zuordnung zu den Richtlinien ist in `mapping-iso.json` gefuehrt. diff --git a/seed/isms-vorlagenpaket-v2/Technische-Sicherheits-Baseline.md b/seed/isms-vorlagenpaket-v2/Technische-Sicherheits-Baseline.md new file mode 100644 index 0000000..c158625 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/Technische-Sicherheits-Baseline.md @@ -0,0 +1,113 @@ +# Technische Sicherheits-Baseline + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Vorgabedokument (Baseline) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + +## Zweck + +Dieses Dokument legt die **konkreten technischen Mindestparameter** der Informationssicherheit fest. Es ist die zentrale Pflegestelle für alle messbaren Werte (Passwortlängen, Fristen, Verfahren). Die Richtlinien R01–R14 verweisen für exakte Werte auf die hier vergebenen **Baseline-IDs** (z. B. `BL-IAM-01`) und wiederholen die Kernaussage konkret im jeweiligen Umsetzungstext. + +Änderungen an Parametern erfolgen ausschließlich hier und werden von {{ROLE_ISB}} freigegeben. Die Werte sind als anpassbare Defaults (Variablen) hinterlegt; sie entsprechen dem Stand der Technik (Orientierung u. a. an BSI IT-Grundschutz und aktuellen NIST-Empfehlungen). + +## 1. Identitäts- und Zugriffsmanagement + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-IAM-01 | Passwortvorgaben | Mindestlänge {{PW_MIN_LENGTH}} Zeichen; {{PW_COMPLEXITY}}; Prüfung gegen bekannte/kompromittierte Passwörter; {{PW_ROTATION}} | +| BL-IAM-02 | Mehr-Faktor-Authentifizierung (MFA) | Verpflichtend für {{MFA_SCOPE}} | +| BL-IAM-03 | Sitzungsverwaltung | Automatische Sperre bei Inaktivität: {{SESSION_TIMEOUT}} | +| BL-IAM-04 | Kontosperrung | {{ACCOUNT_LOCKOUT}} | +| BL-IAM-05 | Rezertifizierung von Berechtigungen | {{RECERT_FREQ}}; privilegierte Rechte zusätzlich anlassbezogen | +| BL-IAM-06 | Privilegierte/technische Konten | Getrennte Verwaltung, Einzelzuordnung, verstärkte Protokollierung; Verwaltung über das zentrale Verzeichnis ({{TOOL_IAM}}) | +| BL-IAM-07 | Dokumentationsort IAM | Anträge/Freigaben/Sperrungen im {{TOOL_TICKET}}; Kontenverwaltung im zentralen Verzeichnis ({{TOOL_IAM}}) | + +## 2. Kryptographie und Übertragung + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-CRY-01 | Transportverschlüsselung | Mindestens {{TLS_MIN}}; unsichere Protokolle deaktiviert | +| BL-CRY-02 | Zulässige Algorithmen/Schlüssellängen | {{CRYPTO_ALGO}} | +| BL-CRY-03 | Datenträgerverschlüsselung | Vollverschlüsselung mobiler Geräte und Datenträger (AES-256) | +| BL-CRY-04 | E-Mail-/Dateiaustausch | Verschlüsselung schutzbedürftiger Inhalte; sichere Austauschwege vorgegeben | +| BL-CRY-05 | Schlüsselverwaltung | Definierter Lebenszyklus (Erzeugung, Verteilung, Speicherung, Sperrung, Vernichtung){{#if FLAG_CRYPTO_PKI}}; PKI/Zertifikatsverwaltung etabliert{{/if}} | + +## 3. Betriebssicherheit + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-OPS-01 | Patch-SLA | Kritisch: {{PATCH_SLA_CRIT}}; hoch: {{PATCH_SLA_HIGH}}; standard: {{PATCH_SLA_STD}} | +| BL-OPS-02 | Schwachstellen-Scanning | {{VULN_SCAN_FREQ}}; Nachverfolgung im {{TOOL_TICKET}} | +| BL-OPS-03 | Malware-Schutz | {{TECH_MALWARE}} auf allen Endpunkten/Servern; Signatur-/Engine-Update {{MALWARE_UPDATE}} | +| BL-OPS-04 | Protokollierung & Aufbewahrung | Zentrale Protokollierung ({{TECH_SIEM}}); Aufbewahrung {{LOG_RETENTION}}; manipulationsgeschützt | +| BL-OPS-05 | Datensicherung | Schema {{BACKUP_SCHEME}} über {{TECH_BACKUP}}; Aufbewahrung {{BACKUP_RETENTION}} | +| BL-OPS-06 | Wiederherstellungstests | {{BACKUP_TEST_FREQ}}; Ergebnis dokumentiert | +| BL-OPS-07 | Systemhärtung | Härtungsvorgaben (z. B. CIS-Benchmarks) für Standardsysteme | +| BL-OPS-08 | Technische Prüfung / Penetrationstest | {{PENTEST_FREQ}} bzw. risikoorientiert | +| BL-OPS-09 | Change-Management | Antrag/Bewertung/Test/Genehmigung/Doku im {{TOOL_TICKET}} | +{{#if FLAG_FW_ISO27001}} +| BL-OPS-10 | Zeitsynchronisation | Systemuhren aller protokollierenden Systeme auf {{NTP_SOURCES}} synchronisiert; Abweichungen werden überwacht | +| BL-OPS-11 | Kapazitätsmanagement | Überwachung der Auslastung (Rechenleistung, Speicher, Bandbreite, Lizenzen) {{CAPACITY_REVIEW_FREQ}}; Schwellenwerte lösen Meldung aus | +| BL-OPS-12 | Schutz vor Datenabfluss | Maßnahmen gegen unbefugten Abfluss schutzbedürftiger Informationen für {{DLP_SCOPE}} | +{{/if}} + +## 4. Netzwerksicherheit + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-NET-01 | Segmentierung | Trennung nach Schutzbedarf; {{#if FLAG_OT_USED}}Produktions-/OT-Netze getrennt und besonders abgesichert; {{/if}}Gäste-/Fremdnetze isoliert | +| BL-NET-02 | Perimeter & Fernzugriff | Firewall mit Default-Deny; Fernzugriff nur über {{TECH_VPN}} mit MFA (BL-IAM-02) | +{{#if FLAG_FW_ISO27001}} +| BL-NET-03 | Web-Filterung | Zugriff auf externe Webinhalte gefiltert (Kategorien, bekannte Schadseiten); Ausnahmen dokumentiert und befristet | +{{/if}} + +## 5. Endpoint und mobile Nutzung + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-EP-01 | Geräteverwaltung | Verwaltung über {{TECH_MDM}}; nur freigegebene Geräte | +| BL-EP-02 | Geräteverschlüsselung/Fernlöschung | Vollverschlüsselung (BL-CRY-03); Sperre/Löschung bei Verlust über {{TECH_MDM}} | +| BL-EP-03 | Wechseldatenträger | Nur verschlüsselt und freigegeben; Nutzung kontrolliert | + +## 6. Physische Sicherheit + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-PHY-01 | Sicherheitszonen | Definierte Zonen; Zutritt bedarfsorientiert, dokumentiert, bei Wegfall entzogen | +| BL-PHY-02 | Zutrittsprotokollierung | Protokollierung zu schutzbedürftigen Bereichen; Besucher registriert und begleitet | +{{#if FLAG_FW_ISO27001}} +| BL-PHY-03 | Umgebungsschutz und Versorgung | Brandfrüherkennung, Schutz gegen Wasser, Temperatur-/Feuchteüberwachung in Technikräumen; unterbrechungsfreie Stromversorgung für kritische Systeme, regelmäßig geprüft | +| BL-PHY-04 | Aufgeräumter Arbeitsplatz und Bildschirmsperre | Schutzbedürftige Unterlagen/Datenträger bei Abwesenheit verschlossen; automatische Bildschirmsperre nach {{SESSION_TIMEOUT}} | +{{/if}} + +## 7. Personal und Lieferanten + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-HR-01 | Awareness/Schulung | Bei Eintritt und danach mindestens {{REVIEW_CYCLE}}; Nachweis im {{TOOL_NAME}} | +| BL-SUP-01 | Lieferanten-Risikoklassen | Einstufung nach Schutzbedarf und Zugriff; Prüfung der Einhaltung (Nachweise/TISAX) | +| BL-DEL-01 | Sichere Löschung | Schutzbedarfsgerechtes Löschen/Vernichten (z. B. nach anerkannten Standards); Löschnachweis | + +## 8. Governance und Projekte + +| ID | Parameter | Vorgabe | +|----|-----------|---------| +| BL-GOV-01 | Audit-/Prüfzyklus | Interne Prüfung {{REVIEW_CYCLE}}; unabhängige Prüfung/Assessment mindestens alle 3 Jahre bzw. nach grundlegenden Änderungen | +| BL-PROJ-01 | Projekt-Klassifizierungskriterien | Dokumentierter Kriterienkatalog zur IS-Klassifizierung von Projekten (Auslöser/Schwellen für ISB-Einbindung) | +{{#if FLAG_FW_ISO27001}} +| BL-GOV-02 | Managementbewertung | Bewertung des ISMS durch die Leitung {{MGMT_REVIEW_CYCLE}} anhand fester Tagesordnung; Beschlüsse mit Verantwortlichem und Termin | +| BL-GOV-03 | Dokumentenlenkung | Prüfzyklus der Leitlinie/Richtlinien {{POLICY_REVIEW_CYCLE}}; Freigabe im Vier-Augen-Prinzip; Aufbewahrung abgelöster Fassungen {{RECORDS_RETENTION}} | +{{/if}} + +## Änderungshistorie + +| Version | Datum | Autor | Änderung | +|---------|-------|-------|----------| +| {{DOC_VERSION}} | {{DOC_DATE}} | {{ROLE_IT_LEAD}} | Erstellung | diff --git a/seed/isms-vorlagenpaket-v2/_enrich.py b/seed/isms-vorlagenpaket-v2/_enrich.py new file mode 100644 index 0000000..2057bc2 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_enrich.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +"""Ersetzt die Umsetzungstexte (IMPL) durch auditfeste, konkrete Fassungen mit +Baseline-Referenzen (BL-*), Werten (als Variablen) und Dokumentationsort. +Patcht die .md-Dateien und aktualisiert mapping.json. Fuegt {{LINK:BASELINE}} ein.""" +import json, re, glob, os +BASE=os.path.dirname(__file__) + +IMPL={ +# R01 +"1.2.1-M1":"Der ISMS-Geltungsbereich (Organisation, Standorte, Prozesse) ist im ISMS-Tool ({{TOOL_NAME}}) dokumentiert, versioniert und wird dort gepflegt; wesentliche Änderungen gibt {{ROLE_ISB}} frei.", +"1.2.1-M2":"Die {{ROLE_MANAGEMENT}} hat das ISMS per Managementbeschluss beauftragt, stellt Personal- und Budgetressourcen bereit und trägt die Gesamtverantwortung; die operative Steuerung liegt bei {{ROLE_ISB}}.", +"1.2.1-M3":"Die Wirksamkeit wird mindestens {{REVIEW_CYCLE}} in einer dokumentierten Managementbewertung anhand von Zielen, Kennzahlen sowie Audit- und Vorfallsergebnissen geprüft; Protokoll und Maßnahmen werden im ISMS-Tool ({{TOOL_NAME}}) abgelegt.", +"1.2.1-S1":"Messbare Informationssicherheitsziele und KPI (z. B. Schulungsquote, offene Maßnahmen, Patch-Compliance) sind definiert und werden im ISMS-Tool ({{TOOL_NAME}}) nachverfolgt.", +"1.2.2-M1":"Verantwortlichkeiten sind in der Rollen-/Verantwortungsmatrix (Abschnitt 5) und im ISMS-Tool ({{TOOL_NAME}}) dokumentiert und den Rolleninhabern kommuniziert.", +"1.2.2-M2":"Die Rolle {{ROLE_ISB}} ist schriftlich benannt, mit Zeit-/Budgetressourcen und Weisungsrechten ausgestattet und berichtet direkt an die {{ROLE_MANAGEMENT}}.", +"1.2.2-S1":"In Konflikt stehende Tätigkeiten (Umsetzung vs. Kontrolle, Beantragung vs. Genehmigung) sind getrennt; unvermeidbare Doppelrollen werden dokumentiert und durch kompensierende Kontrollen (Vier-Augen-Prinzip) abgesichert.", +"1.2.2-S2":"Kontakte zu Behörden, CERT/CSIRT und relevanten Branchengremien werden von {{ROLE_ISB}} gepflegt und im ISMS-Tool hinterlegt.", +"1.2.3-M1":"Projekte werden zu Beginn anhand eines Kriterienkatalogs hinsichtlich Informationssicherheitsbedarf bewertet und klassifiziert; die Einstufung wird im {{TOOL_TICKET}} bzw. ISMS-Tool dokumentiert.", +"1.2.3-M2":"Bei erhöhtem Schutzbedarf wird {{ROLE_ISB}} verbindlich eingebunden; ermittelte Sicherheitsanforderungen werden als Aufgaben im {{TOOL_TICKET}} nachgehalten und vor Projektabschluss geprüft.", +"1.2.3-S1":"Der Kriterienkatalog zur Projekteinstufung ist dokumentiert und wird einheitlich angewandt.", +# R02 +"1.3.1-M1":"Informationswerte und Assets werden im ISMS-Tool ({{TOOL_NAME}}) im Asset-Inventar mit Attributen (Owner, Standort, Schutzbedarf) erfasst; Zu-/Abgänge werden über {{TOOL_TICKET}} ausgelöst.", +"1.3.1-M2":"Jedem Asset ist im Inventar ein verantwortlicher Owner zugeordnet, der Klassifizierung und Aktualität verantwortet.", +"1.3.1-S1":"Das Asset-Inventar wird laufend gepflegt und mindestens {{REVIEW_CYCLE}} vollständig auf Aktualität geprüft (Review durch {{ROLE_IT_LEAD}}).", +"1.3.2-M1":"Es gilt ein vierstufiges Klassifizierungsschema (Öffentlich / Intern / Vertraulich / Streng vertraulich); die Einstufung nach Vertraulichkeit, Integrität und Verfügbarkeit erfolgt durch den Asset Owner im ISMS-Tool.", +"1.3.2-M2":"Je Schutzklasse sind Handhabungsvorgaben zu Kennzeichnung, Speicherung, Übertragung (BL-CRY-01/04) und Löschung (BL-DEL-01) definiert und den Mitarbeitenden bekannt gemacht.", +"1.3.2-S1":"Bei wesentlichen Änderungen wird die Klassifizierung durch den Asset Owner überprüft und im ISMS-Tool aktualisiert.", +"1.3.3-M1":"Externe Hardware/IT-Komponenten werden vor Einsatz technisch und sicherheitsseitig bewertet und freigegeben; die Freigabeliste wird im ISMS-Tool ({{TOOL_NAME}}) geführt.", +"1.3.3-S1":"Der Anschluss nicht freigegebener Geräte wird soweit möglich technisch unterbunden (z. B. Portkontrolle, {{TECH_MDM}}).", +"1.3.4-M1":"Software wird vor Einsatz freigegeben; eine Liste zugelassener Software (Whitelist) wird im ISMS-Tool gepflegt, Beschaffung/Freigabe läuft über {{TOOL_TICKET}}.", +"1.3.4-S1":"Die Installation von Software ist für Standardnutzer technisch eingeschränkt (keine lokalen Adminrechte); Ausnahmen werden im {{TOOL_TICKET}} genehmigt.", +# R03 +"1.4.1-M1":"Das Risikomanagement-Verfahren (Identifikation, Analyse, Bewertung, Behandlung) ist dokumentiert; Risiken werden im ISMS-Tool ({{TOOL_NAME}}) im Risikoregister geführt.", +"1.4.1-M2":"Je Risiko sind Eintrittswahrscheinlichkeit, Schadenshöhe, Behandlungsoption (reduzieren/vermeiden/übertragen/akzeptieren), Maßnahmen, Verantwortlicher und Termin hinterlegt.", +"1.4.1-M3":"Die Bewertung wird mindestens {{REVIEW_CYCLE}} und anlassbezogen (neue Systeme, Vorfälle, Änderungen) aktualisiert; Restrisiken werden von der {{ROLE_MANAGEMENT}} dokumentiert akzeptiert.", +"1.4.1-S1":"Bewertungsskalen und Akzeptanzschwellen sind definiert und im ISMS-Tool hinterlegt.", +"1.5.1-M1":"Die Einhaltung wird durch interne Audits und stichprobenartige Kontrollen (nach Auditplan) geprüft; Feststellungen werden im ISMS-Tool als Maßnahmen nachverfolgt.", +"1.5.1-S1":"Ein jährliches Auditprogramm mit Umfang, Turnus und Verantwortlichkeiten ist etabliert.", +"1.5.2-M1":"Das ISMS wird durch eine unabhängige Stelle (interne Revision oder externe Auditierung, z. B. TISAX) überprüft.", +"1.5.2-S1":"Die Ergebnisse werden in der Managementbewertung behandelt und fließen in den kontinuierlichen Verbesserungsprozess ein.", +# R04 +"1.6.1-M1":"Sicherheitsereignisse können über einen definierten Meldeweg (Meldebutton/Formular im {{TOOL_TICKET}} bzw. ISMS-Tool sowie per E-Mail an {{ROLE_ISB}}) gemeldet werden.", +"1.6.1-M2":"Der Meldeweg ist allen Beschäftigten über Onboarding und Awareness (BL-HR-01) bekannt und niedrigschwellig, auch anonym, erreichbar.", +"1.6.1-S1":"Meldungen werden zentral im ISMS-Tool erfasst, kategorisiert und einem Schweregrad zugeordnet.", +"1.6.2-M1":"Ereignisse werden nach einem definierten Incident-Verfahren bewertet, priorisiert, eingedämmt, behoben und dokumentiert; die Bearbeitung erfolgt im {{TOOL_TICKET}}.", +"1.6.2-M2":"Verantwortlichkeiten und Eskalationsstufen sind definiert; {{ROLE_ISB}} koordiniert, {{ROLE_IT_LEAD}} setzt technische Maßnahmen um.", +"1.6.2-S1":"Nach relevanten Vorfällen erfolgt eine Nachbereitung (Lessons Learned) mit Ableitung und Nachverfolgung von Verbesserungsmaßnahmen.", +"1.6.2-S2":"Vertragliche und gesetzliche Meldepflichten (Kunden/OEM, Aufsichtsbehörden, bei personenbezogenen Daten binnen 72 Stunden) sind im Verfahren berücksichtigt.", +"1.6.3-M1":"Ein Krisenmanagement mit Krisenstab, Rollen, Kommunikations- und Entscheidungswegen ist definiert; der Krisenstab wird durch die {{ROLE_MANAGEMENT}} einberufen.", +"1.6.3-S1":"Krisen- und Notfallpläne werden mindestens {{REVIEW_CYCLE}} geübt (z. B. Tabletop-Übung) und aktualisiert.", +"5.2.8-M1":"Für kritische IT-Dienste bestehen Wiederanlaufziele (RTO/RPO), Verantwortliche und Maßnahmen; {{ROLE_IT_LEAD}} verantwortet die Kontinuitätsplanung.", +"5.2.8-S1":"Wiederanlaufmaßnahmen werden mindestens {{BACKUP_TEST_FREQ}} getestet (BL-OPS-06); Ergebnisse werden dokumentiert.", +# R05 +"2.1.1-M1":"Für sensible Tätigkeiten werden Qualifikation und Zuverlässigkeit im rechtlich zulässigen Rahmen sichergestellt (z. B. Qualifikationsnachweise, bei besonders schutzbedürftigen Rollen ggf. Führungszeugnis).", +"2.1.1-S1":"Sicherheitsanforderungen an Positionen sind in Stellenbeschreibungen hinterlegt; Überprüfungen erfolgen anlass- und rollenbezogen.", +"2.1.2-M1":"Alle Beschäftigten werden bei Eintritt vertraglich zur Vertraulichkeit und Einhaltung der Informationssicherheit verpflichtet ({{ROLE_HR_LEAD}}); der Nachweis wird in der Personalakte geführt.", +"2.1.2-S1":"Die Vertraulichkeitsverpflichtung gilt nachvertraglich fort; Rückgabe von Assets und Entzug von Berechtigungen beim Austritt sind über {{TOOL_TICKET}} geregelt (Leaver-Prozess).", +"2.1.3-M1":"Beschäftigte werden bei Eintritt und danach mindestens {{REVIEW_CYCLE}} geschult (BL-HR-01); Teilnahmenachweise werden im {{TOOL_NAME}} geführt.", +"2.1.3-S1":"Schulungen sind rollenspezifisch; die Wirksamkeit wird durch Phishing-Simulationen und gezielte Nachschulungen überprüft.", +# R06 +"2.1.4-M1":"Mobiles Arbeiten ist in einer Regelung festgelegt; der Zugriff erfolgt ausschließlich über {{TECH_VPN}} mit MFA (BL-IAM-02) und freigegebene, verschlüsselte Geräte (BL-CRY-03).", +"2.1.4-M2":"Der Zugriff auf Unternehmensinformationen ist auf verwaltete Geräte ({{TECH_MDM}}) beschränkt; die Nutzung ist an die Einhaltung der Regelung gebunden.", +"2.1.4-S1":"Regeln zu Sichtschutz, Clean-Desk/Clean-Screen und zum Arbeiten in öffentlichen Umgebungen sind definiert und Teil der Awareness (BL-HR-01).", +"3.1.4-M1":"Mobile Geräte sind vollverschlüsselt (BL-CRY-03) und über {{TECH_MDM}} zentral verwaltet; Verlustmeldung erfolgt über den Meldeweg (R04) und {{TOOL_TICKET}}.", +"3.1.4-M2":"Bei Verlust können Geräte über {{TECH_MDM}} gesperrt und aus der Ferne gelöscht werden (BL-EP-02).", +"3.1.4-S1":"Der Einsatz privater Geräte (BYOD) ist geregelt bzw. untersagt; Wechseldatenträger werden nur verschlüsselt und freigegeben zugelassen (BL-EP-03).", +# R07 +"3.1.1-M1":"Sicherheitszonen sind definiert (BL-PHY-01); der Zutritt zu schutzbedürftigen Bereichen (z. B. Serverraum) ist reglementiert und wird protokolliert (BL-PHY-02).", +"3.1.1-M2":"Zutrittsrechte werden bedarfsorientiert über {{TOOL_TICKET}} vergeben, dokumentiert und bei Wegfall (Austritt/Rollenwechsel) entzogen.", +"3.1.1-S1":"Besucher werden registriert und begleitet; technische Schutzmaßnahmen (Zutrittskontrolle, Alarm, Videoüberwachung im rechtlichen Rahmen) sind vorhanden.", +"3.1.3-M1":"Serverräume und Versorgungseinrichtungen (Strom, Klima, Verkabelung) sind zutrittsgeschützt und gegen Ausfall abgesichert.", +"3.1.3-S1":"Versorgungseinrichtungen werden gewartet und überwacht; für kritische Bereiche bestehen Redundanzen (z. B. USV, Klimaredundanz).", +# R08 +"4.1.1-M1":"Identifikationsmittel (Benutzerkennungen, Token, Zertifikate) werden eindeutig personenbezogen über {{TOOL_IAM}} vergeben; Sammelkonten werden vermieden bzw. dokumentiert und begründet.", +"4.1.1-S1":"Ausgabe, Rücknahme und Sperrung von Identifikationsmitteln werden im {{TOOL_TICKET}} beantragt, genehmigt und dokumentiert (BL-IAM-07).", +"4.1.2-M1":"Der Zugang ist durch sichere Authentifizierung geschützt; die Passwortvorgaben nach BL-IAM-01 (mind. {{PW_MIN_LENGTH}} Zeichen, {{PW_COMPLEXITY}}, {{PW_ROTATION}}) werden zentral über {{TOOL_IAM}} erzwungen.", +"4.1.2-M2":"Für Fernzugriffe, administrative Zugänge und Cloud-Dienste wird MFA gemäß BL-IAM-02 über {{TECH_MFA}} durchgesetzt.", +"4.1.2-S1":"Sperrmechanismen (BL-IAM-04) und Sitzungs-Timeouts (BL-IAM-03) sind zentral konfiguriert.", +"4.1.3-M1":"Konten werden über einen definierten Lebenszyklus (Joiner/Mover/Leaver) verwaltet; Auslöser sind {{TOOL_TICKET}}-Aufträge aus HR-/Vorgesetztenmeldungen.", +"4.1.3-S1":"Privilegierte und technische Konten werden gesondert verwaltet, einzeln zugeordnet und verstärkt protokolliert (BL-IAM-06).", +"4.2.1-M1":"Zugriffsrechte werden nach dem Minimalprinzip (need-to-know/least privilege) vergeben; Antrag, fachliche Prüfung und Genehmigung erfolgen im {{TOOL_TICKET}}.", +"4.2.1-M2":"Berechtigungen werden beim Wegfall entzogen und mindestens {{RECERT_FREQ}} rezertifiziert (BL-IAM-05){{#if FLAG_CUSTOMER_SYSTEMS}}, auch für Zugriffe in Kundensystemen{{/if}}.", +"4.2.1-S1":"Berechtigungen werden rollenbasiert (RBAC) über {{TOOL_IAM}} vergeben; Standardkonten erhalten keine privilegierten Rechte.", +# R09 +"5.1.1-M1":"Zulässige Verfahren und Schlüssellängen nach BL-CRY-02 ({{CRYPTO_ALGO}}) sind vorgegeben; veraltete Verfahren sind untersagt.", +"5.1.1-M2":"Schlüssel werden über ihren Lebenszyklus (Erzeugung, Verteilung, Speicherung, Sperrung, Vernichtung) sicher verwaltet (BL-CRY-05).", +"5.1.1-S1":"Ein Kryptokonzept ist dokumentiert{{#if FLAG_CRYPTO_PKI}}; eine PKI/Zertifikatsverwaltung ist etabliert{{/if}}.", +"5.1.2-M1":"Informationen werden schutzbedarfsgerecht bei der Übertragung geschützt: mindestens {{TLS_MIN}} (BL-CRY-01) und gesicherte Kanäle.", +"5.1.2-S1":"Regeln für E-Mail-Verschlüsselung und sichere Dateiübertragung sind definiert (BL-CRY-04).", +# R10 +"5.2.1-M1":"Änderungen durchlaufen ein Change-Verfahren mit Antrag, Risikobewertung, Test, Genehmigung und Dokumentation im {{TOOL_TICKET}} (BL-OPS-09).", +"5.2.2-M1":"Entwicklung, Test und Produktion sind getrennt betrieben.", +"5.2.2-S1":"Produktivdaten werden in Test-/Entwicklungsumgebungen nur anonymisiert/pseudonymisiert genutzt.", +"5.2.3-M1":"Malware-Schutz ist über {{TECH_MALWARE}} auf allen Endpunkten und Servern umgesetzt (BL-OPS-03).", +"5.2.3-S1":"Signaturen/Engines werden {{MALWARE_UPDATE}} aktualisiert; unnötige Netzwerkdienste sind deaktiviert.", +"5.2.4-M1":"Sicherheitsrelevante Ereignisse werden zentral über {{TECH_SIEM}} protokolliert und ausgewertet (BL-OPS-04).", +"5.2.4-S1":"Protokolle sind manipulationsgeschützt; die Aufbewahrung beträgt {{LOG_RETENTION}}.", +"5.2.5-M1":"Schwachstellen werden erfasst und nach BL-OPS-01 risikoorientiert gepatcht (kritisch {{PATCH_SLA_CRIT}}); die Nachverfolgung erfolgt im {{TOOL_TICKET}}.", +"5.2.5-S1":"Ein Schwachstellen-Scanning ({{VULN_SCAN_FREQ}}, BL-OPS-02) ist etabliert.", +"5.2.6-M1":"Systeme werden nach Härtungsvorgaben (BL-OPS-07, z. B. CIS-Benchmarks) konfiguriert und risikoorientiert technisch geprüft (Penetrationstest {{PENTEST_FREQ}}, BL-OPS-08).", +"5.2.7-M1":"Das Netzwerk ist nach Schutzbedarf segmentiert (BL-NET-01), zugangskontrolliert und nach außen über Firewall (Default-Deny, BL-NET-02) abgesichert.", +"5.2.7-M2":"Produktions-/OT-Netze sind von Office-Netzen getrennt und besonders abgesichert (BL-NET-01).", +"5.2.7-S1":"Ein aktueller Netzplan und ein Segmentierungskonzept werden gepflegt.", +"5.2.9-M1":"Daten und Dienste werden nach Schema {{BACKUP_SCHEME}} über {{TECH_BACKUP}} gesichert (BL-OPS-05); die Wiederherstellung ist geregelt.", +"5.2.9-M2":"Wiederherstellungstests werden mindestens {{BACKUP_TEST_FREQ}} durchgeführt und dokumentiert (BL-OPS-06).", +"5.2.9-S1":"Backups werden geschützt und ausgelagert aufbewahrt (offline/immutable), Aufbewahrung {{BACKUP_RETENTION}}.", +# R11 +"5.3.1-M1":"Sicherheitsanforderungen sind fester Bestandteil von Beschaffungs- und Änderungsprozessen (Security by Design); die Prüfung erfolgt vor Freigabe im {{TOOL_TICKET}}.", +"5.3.1-M2":"Für die Eigenentwicklung gelten Secure-Coding-Vorgaben mit Code-Reviews, automatisierten Sicherheitstests (SAST/Dependency-Scan) und dokumentierten Freigaben.", +"5.3.1-S1":"Sicherheitsanforderungen werden dokumentiert und ihre Umsetzung vor Produktivsetzung geprüft.", +"5.3.2-M1":"Für genutzte Netzdienste (intern/extern) sind Sicherheitsanforderungen definiert und vertraglich bzw. technisch vereinbart.", +"5.3.3-M1":"Rückgabe und sichere Löschung/Vernichtung (bei Vertragsende, Geräteausmusterung) sind nach BL-DEL-01 geregelt und werden nachgewiesen.", +"5.3.3-S1":"Löschverfahren richten sich nach dem Schutzbedarf; Löschungen werden dokumentiert (Löschprotokoll).", +# R12 +"5.3.4-M1":"Bei geteilten externen Diensten wird eine wirksame Mandantentrennung gefordert und vertraglich zugesichert; die Prüfung erfolgt vor Freigabe.", +"5.3.4-M2":"Cloud-Dienste werden vor Nutzung bewertet (Schutzbedarf, Datenlokation/EU, Verschlüsselung, Exit) und von {{ROLE_ISB}} freigegeben; die Freigabeliste wird im ISMS-Tool ({{TOOL_NAME}}) geführt.", +"5.3.4-S1":"Das Segregationskonzept des Anbieters wird dokumentiert und bei Änderungen aktualisiert.", +"5.3.4-KI-M1":"Der Einsatz von KI-/GenAI-Diensten ist geregelt; nur von {{ROLE_ISB}} freigegebene Dienste (Freigabeliste im ISMS-Tool) dürfen genutzt werden.", +"5.3.4-KI-M2":"Zulässige Datenklassen je KI-Dienst sind definiert; die Eingabe vertraulicher oder personenbezogener Daten in nicht freigegebene Dienste ist untersagt (Awareness BL-HR-01).", +"5.3.4-KI-M3":"Bei Freigabe wird geprüft und vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder an Dritte weitergegeben werden (Opt-out bzw. Enterprise-Vertrag).", +"5.3.4-KI-S1":"KI-Ergebnisse werden vor geschäftskritischer Verwendung durch Menschen geprüft (Human-in-the-Loop); der KI-Einsatz wird dokumentiert und regulatorische Anforderungen (EU AI Act) berücksichtigt.", +# R13 +"6.1.1-M1":"Sicherheitsanforderungen an Lieferanten werden ermittelt, vertraglich vereinbart und überwacht; das Lieferantenverzeichnis wird im ISMS-Tool ({{TOOL_NAME}}) geführt.", +"6.1.1-M2":"Lieferanten werden risikoorientiert nach BL-SUP-01 (Schutzbedarf, Zugriff) klassifiziert.", +"6.1.1-S1":"Die Einhaltung wird risikobasiert überprüft (Selbstauskunft, Nachweise, Audits, TISAX-Label).", +"6.1.2-M1":"Vor dem Austausch schutzbedürftiger Informationen werden Vertraulichkeitsvereinbarungen (NDA) abgeschlossen und im ISMS-Tool hinterlegt.", +"6.1.2-S1":"Standardisierte NDA-Vorlagen mit Geltungsdauer sowie Rückgabe-/Löschpflichten werden verwendet.", +"6.1.3-M1":"Die Verantwortlichkeiten mit externen IT-Dienstleistern (Betriebs-, Sicherheits-, Melde- und Mitwirkungspflichten) sind abgegrenzt und vertraglich dokumentiert.", +"6.1.3-S1":"Schnittstellen sowie Eskalations- und Meldewege sind vertraglich vereinbart (Anbindung an R04).", +# R14 +"7.1.1-M1":"Relevante gesetzliche, regulatorische und vertragliche Anforderungen werden in einem Compliance-/Rechtsregister im ISMS-Tool ({{TOOL_NAME}}) erfasst und ihre Einhaltung nachverfolgt.", +"7.1.1-S1":"Das Register wird mindestens {{REVIEW_CYCLE}} aktualisiert; je Anforderung ist ein Verantwortlicher benannt.", +"7.1.2-M1":"Datenschutzrechtliche Anforderungen (DSGVO) werden berücksichtigt; {{ROLE_DPO}} ist eingebunden und bei relevanten Vorhaben (Datenschutz-Folgenabschätzung) beteiligt.", +"7.1.2-M2":"Das Verzeichnis der Verarbeitungstätigkeiten wird im ISMS-Tool ({{TOOL_NAME}}) geführt und gepflegt.", +"7.1.2-S1":"Technische und organisatorische Maßnahmen (TOM), Löschkonzepte (BL-DEL-01) und Prozesse für Betroffenenrechte sind geregelt.", +} + +def clean(s): + s=re.sub(r"\{\{#if \w+\}\}","",s); s=re.sub(r"\{\{/if\}\}","",s) + s=re.sub(r"\s+"," ",s).strip().replace(" .",".").replace(" ,",",") + return s + +# --- Patch .md-Dateien: Zeile nach ersetzen --- +patched=0 +for fp in glob.glob(os.path.join(BASE,"richtlinien/*.md")): + lines=open(fp,encoding="utf-8").read().split("\n") + out=[]; i=0 + while i\s*$", lines[i]) + if m and m.group(1) in IMPL and i+1" +S_ISO_A, S_ISO_E = "", "" +S_SEC_A, S_SEC_E = "", "" +S_REF_E = "" + +# Zwischenueberschriften, die NUR im Parallelbetrieb (beide Frameworks aktiv) erscheinen. +LBL_TIS = "{{#if FLAG_FW_ISO27001}}%s{{/if}}" % L["lbl_tis"] +LBL_ISO = "{{#if FLAG_FW_TISAX}}%s{{/if}}" % L["lbl_iso"] + +# ── Neue ISO-only-Abschnitte: Titel + Umsetzungstext ────────────────────── +# Redaktionell gepflegt in _iso_sections.json (Reihenfolge = Reihenfolge im Dokument). +_sec = json.load(open(os.path.join(BASE, L["sections"]), encoding="utf-8"))["abschnitte"] +NEW_SECTIONS = collections.OrderedDict((k, (v["titel"], v["umsetzung"])) for k, v in _sec.items()) + + +def strip_generated(text): + """Erzeugte Bloecke entfernen — macht den Lauf idempotent.""" + # ISO-Abschnitte + text = re.sub(re.escape(S_SEC_A) + r".*?" + re.escape(S_SEC_E) + r"\n?", "", text, flags=re.S) + # ISO-Anforderungsbloecke + text = re.sub(re.escape(S_ISO_A) + r".*?" + re.escape(S_ISO_E) + r"\n?", "", text, flags=re.S) + # TISAX-Klammer zurueckbauen (Inhalt behalten) + def unwrap(m): + lines = m.group(1).split("\n") + if lines and lines[0] == "{{#if FLAG_FW_TISAX}}": lines.pop(0) + if lines and lines[0] == LBL_TIS: lines.pop(0) # Label nur im Parallelbetrieb, sprachabhaengig + if lines and lines[0] == "": lines.pop(0) + while lines and lines[-1] == "": lines.pop() + if lines and lines[-1] == "{{/if}}": lines.pop() + return "\n".join(lines) + "\n" + text = re.sub(re.escape(S_TIS_A) + r"\n(.*?)" + re.escape(S_TIS_E) + r"\n", unwrap, text, flags=re.S) + # Referenzzeile entfernen und die urspruengliche Ueberschriften-Klammer wiederherstellen. + # Der Start-Sentinel traegt das Original mit, damit der Rueckbau exakt ist. + # Rueckwaertskompatibel: fruehere Fassung trug den Bezug noch in der Ueberschrift. + text = re.sub(r"^(### .*?) \{\{#if FLAG_FW_TISAX\}\}(\(ISA [^)]*\))\{\{/if\}\}.*$", + r"\1 \2", text, flags=re.M) + lines = text.split("\n") + out, last_head = [], None + i = 0 + while i < len(lines): + ln = lines[i] + m = re.match(r"^$", ln) + if m: + if last_head is not None: + out[last_head] = out[last_head] + " " + m.group(1) + while i < len(lines) and lines[i] != S_REF_E: + i += 1 + i += 1 # S_REF_E ueberspringen + if i < len(lines) and lines[i] == "": + i += 1 # nachfolgende Leerzeile ebenfalls + continue + if ln.startswith("### "): + last_head = len(out) + out.append(ln) + i += 1 + return "\n".join(out) + + +def iso_bullets(entries): + out = [] + for e in sorted(entries, key=lambda x: x["_sort"]): + out.append("" % e["id"]) + out.append("- **[ISO %s]** %s" % (e["ref"], e["requirement"])) + return out + + +def main(): + cw = json.load(open(os.path.join(BASE, "_iso_crosswalk.json"), encoding="utf-8"))["zuordnung"] + # Struktur ist sprachneutral; Titel und Anforderungstext kommen bei anderen Sprachen + # aus der jeweiligen Textdatei. + if L["texts"]: + tx = json.load(open(os.path.join(BASE, L["texts"]), encoding="utf-8"))["texte"] + fehlend = [e["ref"] for e in cw if e["ref"] not in tx] + if fehlend: + sys.exit("Uebersetzung fehlt fuer: %s" % ", ".join(fehlend[:5])) + for e in cw: + e["title"] = tx[e["ref"]]["title"] + e["requirement"] = tx[e["ref"]]["requirement"] + for e in cw: + parts = re.split(r"[.\-]", e["ref"].replace("A.", "")) + e["_sort"] = (0 if e["kind"] == "clause" else 1, [int(p) if p.isdigit() else 0 for p in parts]) + + by_section = collections.defaultdict(list) # (policy, section) -> entries + for e in cw: + by_section[(e["policy"], e["section"])].append(e) + + changed = [] + # ── 1. Richtlinien patchen ──────────────────────────────────────────────── + for path in sorted(glob.glob(os.path.join(OUT, "richtlinien", "*.md"))): + code = os.path.basename(path).split("_")[0] + raw = open(path, encoding="utf-8").read() + new = strip_generated(raw) + + if code == "L00": + new = patch_l00(new, by_section.get(("L00", "ISO-LEITLINIE"), [])) + else: + new = patch_policy(new, code, by_section) + + if new != raw: + changed.append(os.path.basename(path)) + if not CHECK: + open(path, "w", encoding="utf-8").write(new) + + # ── 2. FULFILLS-Header der Verfahren um ISO-IDs ergaenzen ───────────────── + va_ids = collections.defaultdict(list) + for e in cw: + for va in e["verfahren"]: + va_ids[va].append(e) + for path in sorted(glob.glob(os.path.join(OUT, "verfahren", "*.md"))): + va = os.path.basename(path).split("_")[0] + raw = open(path, encoding="utf-8").read() + m = re.search(r"", raw) + if not m: + continue + existing = [x.strip() for x in m.group(1).split(",") if x.strip()] + base_ids = [x for x in existing if not (x.startswith("A.") or re.match(r"^\d+(\.\d+)*-1$", x))] + iso_new = sorted({e["id"] for e in va_ids.get(va, [])}, key=lambda s: (s.startswith("A."), s)) + merged = base_ids + iso_new + header = "" % (", ".join(merged), m.group(2)) + new = raw[:m.start()] + header + raw[m.end():] + if new != raw: + changed.append(os.path.basename(path)) + if not CHECK: + open(path, "w", encoding="utf-8").write(new) + + # ── 3. mapping-iso.json schreiben ───────────────────────────────────────── + anforderungen = [] + for e in sorted(cw, key=lambda x: x["_sort"]): + impl = "IMPL " + e["section"] + anforderungen.append(collections.OrderedDict([ + ("id", e["id"]), ("policy", e["policy"]), ("control", e["ref"]), + ("kind", e["kind"]), ("title", e["title"]), ("type", "MUSS"), + ("soa_relevant", e["soa_relevant"]), ("applicable", True), + ("condition", e["condition"]), + ("req_anchor", "REQ " + e["id"]), ("impl_anchor", impl), + ("requirement", e["requirement"]), + ("link", "{{LINK:%s#%s}}" % (e["policy"], e["section"])), + ("nachweis_link", "{{LINK:NACHWEISREGISTER}}"), + ("verfahren", e["verfahren"]), + ])) + mapping = collections.OrderedDict([ + ("meta", collections.OrderedDict([ + ("paket", "ISMS-Vorlagenpaket v2 — Framework-Mapping ISO/IEC 27001:2022"), + ("standard", "ISO/IEC 27001:2022 (Kap. 4-10 + Anhang A)"), + ("framework", "ISO_27001"), + ("version", "2.1"), + ("bibliothek", "gemeinsam mit dem VDA-ISA-Mapping (mapping.json) — ein Dokumentensatz, zwei Mappings"), + ("hinweis", "Anforderungstexte sind eigene Paraphrasen (keine woertlichen Normzitate); " + "die Referenzen sind exakt zum Nachschlagen. Der Umsetzungstext wird ueber impl_anchor " + "aus dem jeweiligen Richtlinienabschnitt aufgeloest und ist mit dem VDA-ISA-Mapping geteilt."), + ("coverage", "27 Klausel-Anforderungen (Kap. 4-10) + 93 Anhang-A-Controls = 120 Eintraege"), + ])), + ("anforderungen", anforderungen), + ]) + if not CHECK: + with open(os.path.join(OUT, "mapping-iso.json"), "w", encoding="utf-8") as fh: + json.dump(mapping, fh, ensure_ascii=False, indent=1) + fh.write("\n") + + # ── 4. SoA-Geruest schreiben (Pflichtangaben nach 6.1.3 d) ─────────────── + SOA = L["soa_strings"] + THEMEN = SOA["themen"] + head = SOA["head"] + lines = [ + "# " + SOA["title"], "", + "| %s | %s |" % (head["k"], head["v"]), + "|-----------------------|------|", + "| %s | %s |" % (head["type"], SOA["title"]), + "| %s | {{ISMS_SCOPE}} |" % head["scope"], + "| %s | {{ORG_NAME}} |" % head["org"], + "| %s | {{ROLE_ISB}} |" % head["resp"], + "| %s | {{ROLE_MANAGEMENT}} |" % head["appr"], + "| %s | {{DOC_VERSION}} |" % head["ver"], + "| %s | {{DOC_DATE}} |" % head["date"], + "| %s | {{DOC_STATUS}} |" % head["status"], + "", "## " + SOA["purpose_head"], "", SOA["purpose"], "", SOA["columns"], "", + ] + ctl = [e for e in sorted(cw, key=lambda x: x["_sort"]) if e["kind"] != "clause"] + for pref, titel in THEMEN: + rows = [e for e in ctl if e["ref"].startswith(pref + ".")] + lines += ["## %s %s (%d %s)" % (pref, titel, len(rows), SOA["measures"]), "", + "| " + " | ".join(SOA["cols"]) + " |", + "|---|---|:--:|---|---|---|---|---|---|"] + for e in rows: + va = ", ".join(e["verfahren"]) if e["verfahren"] else "-" + if e["condition"]: + begr = ("{{#if %s}}%s{{/if}}{{#unless %s}}%s{{/unless}}" + % (e["condition"], SOA["incl"], e["condition"], SOA["excl"])) + anw = "{{#if %s}}%s{{/if}}{{#unless %s}}%s{{/unless}}" % ( + e["condition"], SOA["yes"], e["condition"], SOA["no"]) + else: + begr, anw = SOA["incl"], SOA["yes"] + lines.append("| %s | %s | %s | %s | | | {{LINK:%s}} | %s | |" % + (e["ref"], e["title"], anw, begr, e["policy"], va)) + lines.append("") + lines += ["## " + SOA["clauses_head"], "", SOA["clauses"], ""] + if not CHECK: + open(os.path.join(OUT, L["soa"]), "w", encoding="utf-8").write("\n".join(lines)) + + # ── 5. Control-Titel fuer die Oberflaeche erzeugen (B3) ─────────────────── + # Eigene Map: ISA und ISO kollidieren bei 6.1.1-6.1.3 (Lieferanten vs. Risikoklauseln). + ts = ["// AUTOGENERIERT von seed/isms-vorlagenpaket-v2/_generate_iso.py — nicht von Hand aendern.", + "// Quelle: mapping-iso.json. Neu erzeugen: python3 seed/isms-vorlagenpaket-v2/_generate_iso.py", + "//", + "// Eigene Map statt Ergaenzung von CONTROL_TITLES: die Schluessel 6.1.1-6.1.3 sind in", + "// beiden Katalogen belegt (VDA ISA: Lieferanten - ISO: Risikobeurteilung/-behandlung).", + "", + "export const CONTROL_TITLES_ISO: Record = {"] + for e in sorted(cw, key=lambda x: x["_sort"]): + ts.append(' "%s": "%s",' % (e["ref"], e["title"].replace('"', '\\"'))) + ts += ["};", "", + "/** Titel einer ISO/IEC-27001-Anforderung; Fallback: „ISO “. */", + "export function controlTitleIso(ref: string): string {", + " return CONTROL_TITLES_ISO[ref] ?? `ISO ${ref}`;", + "}", ""] + out_ts = os.path.join(BASE, "..", "..", "src", "lib", "control-titles-iso.ts") + if not CHECK and LANG == "de": + with open(os.path.normpath(out_ts), "w", encoding="utf-8") as fh: + fh.write("\n".join(ts)) + + # ── 6. ISO -> VDA-ISA-Crosswalk fuer die Oberflaeche (B2) ──────────────── + # Erlaubt es, die vorhandenen C6-Umsetzungshinweise (nach ISA-Control verschluesselt) + # auch fuer ISO-Anforderungen anzuzeigen, ohne den Hinweiskatalog zu duplizieren. + pairs = [(e["ref"], e["section"]) for e in sorted(cw, key=lambda x: x["_sort"]) + if not e["section"].startswith("ISO-")] + only = [e["ref"] for e in sorted(cw, key=lambda x: x["_sort"]) if e["section"].startswith("ISO-")] + cx = ["// AUTOGENERIERT von seed/isms-vorlagenpaket-v2/_generate_iso.py — nicht von Hand aendern.", + "// Quelle: _iso_crosswalk.json. Neu erzeugen: python3 seed/isms-vorlagenpaket-v2/_generate_iso.py", + "//", + "// Zuordnung ISO-Anforderung -> VDA-ISA-Control desselben Bibliotheksabschnitts.", + "// Zweck: die vorhandenen Umsetzungshinweise (ImplementationHint, nach ISA-Control", + "// verschluesselt) fuer ISO-Anforderungen wiederverwenden, statt sie zu duplizieren.", + "// ISO-Anforderungen ohne Eintrag liegen in einem ISO-eigenen Abschnitt — fuer sie", + "// gibt es (noch) keine Hinweise.", + "", + "export const ISO_TO_ISA: Record = {"] + for ref, sec in pairs: + cx.append(' "%s": "%s",' % (ref, sec)) + cx += ["};", "", + "/** ISO-Anforderungen, die in einem ISO-eigenen Abschnitt liegen (kein ISA-Gegenstueck). */", + "export const ISO_ONLY: readonly string[] = [", + " " + ", ".join('"%s"' % r for r in only) + ",", + "];", "", + "/** ISA-Control, dessen Umsetzungshinweise fuer diese ISO-Anforderung gelten (oder null). */", + "export function isaControlForIso(ref: string): string | null {", + " return ISO_TO_ISA[ref] ?? null;", + "}", ""] + out_cx = os.path.normpath(os.path.join(BASE, "..", "..", "src", "lib", "iso-isa-crosswalk.ts")) + if not CHECK and LANG == "de": + with open(out_cx, "w", encoding="utf-8") as fh: + fh.write("\n".join(cx)) + + # ── 7. Control-Specs fuer die ISO-Bewertung (Belegbasis, B1) ───────────── + # Framework-neutrale Belegspezifikation je ISO-Control: zustaendige Richtlinie/ + # Verfahren aus dem Mapping; needsAsset/needsRisk via ISO_TO_ISA vom ISA-Spec + # (seed/scoping/c5-controls.json) geerbt, fuer die ISO-eigenen Abschnitte explizit. + c5 = json.load(open(os.path.normpath(os.path.join(BASE, "..", "scoping", "c5-controls.json")), encoding="utf-8")) + c5_by = {c["control"]: c for c in c5} + ASSET_OVERRIDE = {"A.5.9"} + RISK_OVERRIDE = {"6.1.2", "6.1.3", "8.2", "8.3"} + sp = ["// AUTOGENERIERT von seed/isms-vorlagenpaket-v2/_generate_iso.py — nicht von Hand aendern.", + "// Quelle: mapping-iso.json + seed/scoping/c5-controls.json. Neu erzeugen: python3 seed/isms-vorlagenpaket-v2/_generate_iso.py", + "//", + "// Belegspezifikation je ISO-Control (Feindesign §1/§2, B1): welche Richtlinie/Verfahren", + "// zustaendig sind und ob Asset-/Risiko-Verknuepfung gefordert ist. needsAsset/needsRisk", + "// werden ueber ISO_TO_ISA vom ISA-Spec geerbt; ISO-eigene Abschnitte explizit gesetzt.", + "// Strukturgleich zu ControlSpec (src/lib/maturity.ts) — von der GETEILTEN Belegbasis konsumiert.", + "", + "export interface IsoControlSpec {", + " control: string;", + " title: string;", + " policy: string[];", + " verfahren: string[];", + " needsAsset: boolean;", + " needsRisk: boolean;", + "}", + "", + "const SPECS: Record = {"] + for e in sorted(cw, key=lambda x: x["_sort"]): + ref = e["ref"]; sec = e["section"] + if sec.startswith("ISO-"): + na = nr = False + else: + base = c5_by.get(sec) + na = bool(base["needsAsset"]) if base else False + nr = bool(base["needsRisk"]) if base else False + if ref in ASSET_OVERRIDE: na = True + if ref in RISK_OVERRIDE: nr = True + pol = '["%s"]' % e["policy"] if e["policy"] else "[]" + vf = "[" + ", ".join('"%s"' % v for v in e["verfahren"]) + "]" + sp.append(' "%s": { control: "%s", title: "%s", policy: %s, verfahren: %s, needsAsset: %s, needsRisk: %s },' + % (ref, ref, e["title"].replace('"', '\\"'), pol, vf, str(na).lower(), str(nr).lower())) + sp += ["};", "", + "/** Belegspezifikation eines ISO-Controls; Fallback fuer unbekannte Controls. */", + "export function controlSpecIso(control: string): IsoControlSpec {", + " return SPECS[control] ?? { control, title: `ISO ${control}`, policy: [], verfahren: [], needsAsset: false, needsRisk: false };", + "}", + "", + "/** Alle ISO-Controls mit Belegspezifikation (Klauseln 4-10 + Anhang A). */", + "export const ISO_SPEC_CONTROLS: readonly string[] = Object.keys(SPECS);", + ""] + out_sp = os.path.normpath(os.path.join(BASE, "..", "..", "src", "lib", "control-specs-iso.ts")) + if not CHECK and LANG == "de": + with open(out_sp, "w", encoding="utf-8") as fh: + fh.write("\n".join(sp)) + + print("Geaenderte Dateien:", len(changed)) + for c in changed: + print(" ", c) + print("mapping-iso.json:", len(anforderungen), "Anforderungen") + print("Statement-of-Applicability-ISO.md:", len(ctl), "Controls") + print("src/lib/control-titles-iso.ts:", len(cw), "Titel") + print("src/lib/iso-isa-crosswalk.ts:", len(pairs), "mit ISA-Bezug,", len(only), "ISO-eigen") + return 0 + + +def patch_policy(text, code, by_section): + """Bestehende Abschnitte um ISO-Bloecke ergaenzen und neue ISO-Abschnitte anhaengen.""" + lines = text.split("\n") + out = [] + # Abschnittsgrenzen finden + sec_starts = [j for j, l in enumerate(lines) if l.startswith("### ")] + sec_bounds = [] + for k, s in enumerate(sec_starts): + e = sec_starts[k + 1] if k + 1 < len(sec_starts) else len(lines) + sec_bounds.append((s, e)) + cursor = 0 + for (s, e) in sec_bounds: + out.extend(lines[cursor:s]) + block = lines[s:e] + ctrl = None + for l in block: + m = re.match(r"^", l) + if m and not m.group(1).endswith("-elev"): + ctrl = m.group(1); break + entries = by_section.get((code, ctrl), []) if ctrl else [] + if ctrl: + block = patch_section(block, entries) + out.extend(block) + cursor = e + out.extend(lines[cursor:]) + text = "\n".join(out) + + # Neue ISO-Abschnitte vor „## 4. Verbindlichkeit" einfuegen + new_keys = [k for (p, k) in by_section if p == code and k.startswith("ISO-")] + if new_keys: + order = [k for k in NEW_SECTIONS if k in new_keys] + base_no = 3 + idx = max((int(m.group(2)) for m in re.finditer(r"^### (\d+)\.(\d+)", text, re.M)), default=0) + chunks = [] + for k in order: + idx += 1 + title, impl = NEW_SECTIONS[k] + ents = by_section[(code, k)] + refs = ", ".join(e["ref"] for e in sorted(ents, key=lambda x: x["_sort"])) + chunk = [S_SEC_A, "{{#if FLAG_FW_ISO27001}}", "", + "### %d.%d %s" % (base_no, idx, title), "", + "%s %s %s" % (L["ref_label"], L["iso_name"], refs), "", + L["req"], ""] + chunk += iso_bullets(ents) + chunk += ["", L["impl_head"], "", "" % k, impl, "", + "{{/if}}", S_SEC_E, ""] + chunks.append("\n".join(chunk)) + anchor = re.search(r"^## 4\. Verbindlichkeit", text, re.M) + pos = anchor.start() if anchor else len(text) + text = text[:pos] + "".join(chunks) + text[pos:] + return text + + +def patch_section(block, entries): + """Innerhalb eines Abschnitts: Ueberschrift konditionieren, ISA-Block klammern, ISO-Block anfuegen.""" + refs = ", ".join(e["ref"] for e in sorted(entries, key=lambda x: x["_sort"])) + # 1. Ueberschrift entklammern, Anforderungsbezug in eine eigene Zeile darunter ziehen + m = re.match(r"^(### .*?)\s*(\(ISA [^)]*\))\s*$", block[0]) + if m: + isa = m.group(2)[1:-1].replace("ISA ", L["isa_name"] + " ") + iso = ("%s %s" % (L["iso_name"], refs)) if refs else L["no_annex"] + ref_line = (L["ref_label"] + " {{#if FLAG_FW_TISAX}}%s{{/if}}" + "{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}%s{{/if}}") % (isa, iso) + block[0] = m.group(1) + j = 1 + while j < len(block) and block[j].strip() == "": + j += 1 + block[1:j] = ["", "" % m.group(2), ref_line, S_REF_E, ""] + # 2. Anforderungsbereich abgrenzen + try: + a = next(j for j, l in enumerate(block) if l.strip() == L["req"]) + u = next(j for j, l in enumerate(block) if l.startswith(L["impl"])) + except StopIteration: + return block + start = a + 1 + while start < u and block[start].strip() == "": + start += 1 + end = u + while end - 1 > start and block[end - 1].strip() == "": + end -= 1 + req = block[start:end] + wrapped = [S_TIS_A, "{{#if FLAG_FW_TISAX}}", LBL_TIS, ""] + req + ["{{/if}}", S_TIS_E] + if entries: + wrapped += [S_ISO_A, "{{#if FLAG_FW_ISO27001}}", LBL_ISO, ""] + iso_bullets(entries) + ["{{/if}}", S_ISO_E] + return block[:start] + wrapped + block[end:] + + +def patch_l00(text, entries): + """L00 erhaelt einen ISO-Anhang (Politik, Ziele, Kommunikation, A.5.1).""" + if not entries: + return text + title, impl = NEW_SECTIONS["ISO-LEITLINIE"] + refs = ", ".join(e["ref"] for e in sorted(entries, key=lambda x: x["_sort"])) + chunk = [S_SEC_A, "{{#if FLAG_FW_ISO27001}}", "", + L["appendix"] % title, "", + "%s %s %s" % (L["ref_label"], L["iso_name"], refs), "", + L["req"], ""] + chunk += iso_bullets(entries) + chunk += ["", L["impl_head"], "", "", impl, "", + "{{/if}}", S_SEC_E, ""] + return text.rstrip("\n") + "\n\n" + "\n".join(chunk) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/seed/isms-vorlagenpaket-v2/_generate_v2.py b/seed/isms-vorlagenpaket-v2/_generate_v2.py new file mode 100644 index 0000000..25678d2 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_generate_v2.py @@ -0,0 +1,553 @@ +# -*- coding: utf-8 -*- +""" +Generator ISMS-Vorlagenpaket v2. +Erzeugt: richtlinien/*.md (mit Hidden-IDs + {{LINK:...}}), mapping.json, ISA-Mapping-Matrix. +Konvention: UPPER_SNAKE-Variablen, {{#if FLAG_x}}...{{/if}} Bedingungsbloecke. +""" +import os, json + +BASE = os.path.dirname(__file__) +RDIR = os.path.join(BASE, "richtlinien") +os.makedirs(RDIR, exist_ok=True) + +# --------------------------------------------------------------------------- +# Datenmodell +# control = {"num","title","reqs":[{"t":"M"|"S","req":..,"impl":..}]} +# Jede Anforderung erhaelt eine ID - und Hidden-Anker. +# --------------------------------------------------------------------------- + +POLICIES = [] + +def pol(**k): POLICIES.append(k) + +pol(id="R01", fn="R01_ISMS-Organisation-und-Rollen", + title="ISMS-Organisation und Rollen", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt Aufbau, Steuerung und Verantwortlichkeiten des Informationssicherheits-Managementsystems (ISMS) der {{ORG_NAME}} sowie die Beruecksichtigung der Informationssicherheit in Projekten.", + related=["L00","R03","R13"], + roles=[("{{ROLE_MANAGEMENT}}","Beauftragung und Gesamtverantwortung ISMS, Ressourcen, Managementbewertung"), + ("{{ROLE_ISB}}","Operative Steuerung des ISMS, Pflege der Verantwortlichkeiten"), + ("{{ROLE_IT_LEAD}}","Technische Umsetzung ISMS-relevanter Massnahmen"), + ("Asset Owner / Prozessverantwortliche","Pflege zugeordneter Assets/Prozesse im ISMS-Tool")], + controls=[ + {"num":"1.2.1","title":"Steuerung der Informationssicherheit","reqs":[ + {"t":"M","req":"Der Geltungsbereich des ISMS (Organisation, Standorte, Prozesse) ist bestimmt und dokumentiert.", + "impl":"Der ISMS-Geltungsbereich ist im ISMS-Tool ({{TOOL_NAME}}) dokumentiert und wird dort gepflegt."}, + {"t":"M","req":"Das ISMS wird durch die Leitung initiiert, gesteuert und ueberwacht; erforderliche Ressourcen werden bereitgestellt.", + "impl":"Die {{ROLE_MANAGEMENT}} hat das ISMS beauftragt, stellt die erforderlichen Ressourcen bereit und traegt die Gesamtverantwortung; die operative Steuerung liegt bei {{ROLE_ISB}}."}, + {"t":"M","req":"Die Wirksamkeit des ISMS wird regelmaessig durch die Leitung bewertet (Managementbewertung).", + "impl":"Die Wirksamkeit des ISMS wird mindestens {{REVIEW_CYCLE}} in einer dokumentierten Managementbewertung geprueft; die Ergebnisse werden im ISMS-Tool festgehalten."}, + {"t":"S","req":"Informationssicherheitsziele sind messbar formuliert und werden nachverfolgt (KPI).", + "impl":"Informationssicherheitsziele und Kennzahlen (KPI) sind definiert und werden im ISMS-Tool nachverfolgt."}, + ]}, + {"num":"1.2.2","title":"Organisation der Verantwortlichkeiten","reqs":[ + {"t":"M","req":"Verantwortlichkeiten fuer Informationssicherheit sind definiert, zugewiesen und dokumentiert.", + "impl":"Die Verantwortlichkeiten sind in der Rollenuebersicht (Abschnitt 5) und im ISMS-Tool ({{TOOL_NAME}}) dokumentiert und bekannt gemacht."}, + {"t":"M","req":"Eine fuer Informationssicherheit verantwortliche Rolle ist benannt, verfuegt ueber ausreichende Kompetenzen und einen direkten Berichtsweg zur Leitung.", + "impl":"Die Rolle {{ROLE_ISB}} ist benannt und berichtet direkt an die {{ROLE_MANAGEMENT}}."}, + {"t":"S","req":"In Konflikt stehende Aufgaben und Verantwortungsbereiche sind getrennt (Funktionstrennung).", + "impl":"In Konflikt stehende Taetigkeiten (z. B. Umsetzung und Kontrolle) werden getrennt; unvermeidbare Doppelrollen werden durch kompensierende Kontrollen abgesichert."}, + {"t":"S","req":"Kontakte zu relevanten Behoerden und Interessengruppen werden gepflegt.", + "impl":"Relevante externe Kontakte (Behoerden, CERT, Branchengremien) werden durch {{ROLE_ISB}} gepflegt."}, + ]}, + {"num":"1.2.3","title":"Informationssicherheit in Projekten","reqs":[ + {"t":"M","req":"Projekte werden unter Beruecksichtigung ihres Informationssicherheitsbedarfs klassifiziert.", + "impl":"Projekte werden zu Beginn hinsichtlich ihres Informationssicherheitsbedarfs bewertet und klassifiziert."}, + {"t":"M","req":"In Projekten werden Informationssicherheitsanforderungen ermittelt und beruecksichtigt.", + "impl":"Bei erhoehtem Schutzbedarf wird {{ROLE_ISB}} eingebunden; die Anforderungen werden ermittelt und im ISMS-Tool nachgehalten."}, + {"t":"S","req":"Verfahren und Kriterien zur Klassifizierung von Projekten sind dokumentiert und werden angewandt.", + "impl":"Die Kriterien fuer die Projekteinstufung sind dokumentiert und werden einheitlich angewandt."}, + ]}, + ]) + +pol(id="R02", fn="R02_Asset-und-Klassifizierungsrichtlinie", + title="Asset- und Klassifizierungsrichtlinie", owner="ROLE_IT_LEAD", + purpose="Diese Richtlinie regelt Identifikation, Inventarisierung, Klassifizierung und den geschuetzten Umgang mit Informationswerten und Assets der {{ORG_NAME}} sowie die Zulassung von Hard- und Software.", + related=["R01","R08","R11"], + roles=[("{{ROLE_IT_LEAD}}","Pflege des Asset-Inventars, Zulassung Hard-/Software"), + ("{{ROLE_ISB}}","Vorgabe des Klassifizierungsschemas"), + ("Asset Owner","Bewertung und Pflege einzelner Assets im ISMS-Tool")], + controls=[ + {"num":"1.3.1","title":"Identifikation von Assets","reqs":[ + {"t":"M","req":"Informationswerte und weitere Assets, die Informationen verarbeiten, sind identifiziert und erfasst.", + "impl":"Informationswerte und Assets werden im ISMS-Tool ({{TOOL_NAME}}) im Asset-Inventar erfasst."}, + {"t":"M","req":"Fuer jedes Asset ist ein Verantwortlicher (Owner) benannt.", + "impl":"Jedem Asset ist im ISMS-Tool ein Owner zugeordnet."}, + {"t":"S","req":"Ein Katalog der relevanten Informationswerte wird gepflegt und regelmaessig aktualisiert.", + "impl":"Das Asset-Inventar wird laufend gepflegt und mindestens {{REVIEW_CYCLE}} auf Aktualitaet geprueft."}, + ]}, + {"num":"1.3.2","title":"Klassifizierung","reqs":[ + {"t":"M","req":"Informationswerte sind nach Schutzbedarf (Vertraulichkeit, Integritaet, Verfuegbarkeit) klassifiziert.", + "impl":"Es gilt ein vierstufiges Klassifizierungsschema (Oeffentlich / Intern / Vertraulich / Streng vertraulich); die Einstufung erfolgt im ISMS-Tool."}, + {"t":"M","req":"Abhaengig von der Klassifizierung sind Vorgaben zu Kennzeichnung, Handhabung, Speicherung, Uebertragung und Loeschung definiert.", + "impl":"Handhabungsvorgaben je Schutzklasse sind definiert und den Mitarbeitenden bekannt gemacht."}, + {"t":"S","req":"Die Klassifizierung wird bei wesentlichen Aenderungen ueberprueft und angepasst.", + "impl":"Bei wesentlichen Aenderungen wird die Klassifizierung durch den Asset Owner ueberprueft."}, + ]}, + {"num":"1.3.3","title":"Zugelassene Hardware","reqs":[ + {"t":"M","req":"Es ist sichergestellt, dass nur bewertete und freigegebene externe Hardware/IT-Komponenten eingesetzt werden.", + "impl":"Externe Hardware wird vor Einsatz bewertet und freigegeben; eine Freigabeliste wird im ISMS-Tool gefuehrt."}, + {"t":"S","req":"Nicht freigegebene Geraete werden technisch unterbunden.", + "impl":"Der Anschluss nicht freigegebener Geraete wird soweit moeglich technisch unterbunden."}, + ]}, + {"num":"1.3.4","title":"Zugelassene Software","reqs":[ + {"t":"M","req":"Es ist sichergestellt, dass nur bewertete und freigegebene Software eingesetzt wird.", + "impl":"Software wird vor Einsatz freigegeben; eine Liste zugelassener Software wird gepflegt."}, + {"t":"S","req":"Die Installation nicht freigegebener Software wird technisch eingeschraenkt.", + "impl":"Die Installation von Software ist fuer Standardnutzer technisch eingeschraenkt."}, + ]}, + ]) + +pol(id="R03", fn="R03_Risikomanagement-und-Auditrichtlinie", + title="Risikomanagement- und Auditrichtlinie", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt Identifikation, Bewertung und Behandlung von Informationssicherheitsrisiken sowie die interne und unabhaengige Ueberpruefung des ISMS.", + related=["R01","R04"], + roles=[("{{ROLE_ISB}}","Steuerung des Risikomanagements, Pflege des Risikoregisters"), + ("{{ROLE_MANAGEMENT}}","Entscheidung ueber Risikoakzeptanz"), + ("Asset/Prozessverantwortliche","Mitwirkung bei Risikobewertung")], + controls=[ + {"num":"1.4.1","title":"Risikomanagement","reqs":[ + {"t":"M","req":"Es existiert ein dokumentiertes Verfahren zur Identifikation, Analyse, Bewertung und Behandlung von Informationssicherheitsrisiken.", + "impl":"Das Risikomanagement-Verfahren ist dokumentiert; Risiken werden im ISMS-Tool ({{TOOL_NAME}}) bewertet und nachverfolgt."}, + {"t":"M","req":"Risiken werden in einem Risikoregister erfasst; Behandlungsoptionen und Massnahmen sind festgelegt.", + "impl":"Alle Risiken werden im Risikoregister erfasst; je Risiko sind Behandlungsoption (reduzieren/vermeiden/uebertragen/akzeptieren) und Massnahmen hinterlegt."}, + {"t":"M","req":"Die Risikobewertung wird regelmaessig und anlassbezogen aktualisiert; die Risikoakzeptanz erfolgt durch die Leitung.", + "impl":"Die Bewertung wird mindestens {{REVIEW_CYCLE}} und anlassbezogen aktualisiert; die {{ROLE_MANAGEMENT}} akzeptiert Restrisiken dokumentiert."}, + {"t":"S","req":"Kriterien fuer Eintrittswahrscheinlichkeit, Schadenshoehe und Akzeptanzschwellen sind definiert.", + "impl":"Bewertungs- und Akzeptanzkriterien sind definiert und im ISMS-Tool hinterlegt."}, + ]}, + {"num":"1.5.1","title":"Compliance-Pruefung im IS-Betrieb","reqs":[ + {"t":"M","req":"Die Einhaltung der Informationssicherheitsvorgaben wird regelmaessig geprueft.", + "impl":"Die Einhaltung wird durch interne Audits und Kontrollen regelmaessig geprueft."}, + {"t":"S","req":"Ein Auditprogramm mit Umfang, Turnus und Verantwortlichkeiten ist etabliert; Feststellungen werden nachverfolgt.", + "impl":"Ein Auditprogramm ist etabliert; Feststellungen werden im ISMS-Tool nachverfolgt."}, + ]}, + {"num":"1.5.2","title":"Unabhaengige Ueberpruefung","reqs":[ + {"t":"M","req":"Das ISMS wird durch eine unabhaengige Stelle ueberprueft.", + "impl":"Das ISMS wird durch eine unabhaengige Stelle (interne Revision oder externe Auditierung) ueberprueft."}, + {"t":"S","req":"Ergebnisse fliessen in die Managementbewertung und den Verbesserungsprozess ein.", + "impl":"Die Ergebnisse werden in der Managementbewertung behandelt und fliessen in Verbesserungsmassnahmen ein."}, + ]}, + ]) + +pol(id="R04", fn="R04_Incident-Notfall-und-Kontinuitaetsrichtlinie", + title="Incident-, Notfall- und Kontinuitaetsrichtlinie", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt Meldung und Behandlung von Sicherheitsereignissen, das Krisenmanagement sowie die Notfall- und Kontinuitaetsplanung fuer IT-Dienste.", + related=["R03","R10"], + roles=[("{{ROLE_ISB}}","Koordination der Vorfallsbehandlung"), + ("{{ROLE_IT_LEAD}}","IT-Notfall- und Wiederanlaufplanung"), + ("{{ROLE_MANAGEMENT}}","Einberufung Krisenstab")], + controls=[ + {"num":"1.6.1","title":"Meldung von Ereignissen","reqs":[ + {"t":"M","req":"Sicherheitsrelevante Ereignisse und Beobachtungen koennen ueber einen definierten Meldeweg gemeldet werden.", + "impl":"Ein Meldeweg fuer Sicherheitsereignisse ist eingerichtet (z. B. im ISMS-Tool {{TOOL_NAME}}) und bekannt gemacht."}, + {"t":"M","req":"Der Meldeweg ist bekannt gemacht und niedrigschwellig erreichbar.", + "impl":"Der Meldeweg ist allen Mitarbeitenden bekannt und niedrigschwellig erreichbar."}, + {"t":"S","req":"Meldungen werden zentral erfasst und kategorisiert.", + "impl":"Meldungen werden zentral im ISMS-Tool erfasst und kategorisiert."}, + ]}, + {"num":"1.6.2","title":"Behandlung von Sicherheitsereignissen","reqs":[ + {"t":"M","req":"Gemeldete Sicherheitsereignisse werden bewertet, priorisiert, behandelt und dokumentiert.", + "impl":"Ereignisse werden nach einem definierten Verfahren bewertet, priorisiert, behandelt und im ISMS-Tool dokumentiert."}, + {"t":"M","req":"Verantwortlichkeiten und Eskalationswege fuer die Vorfallsbehandlung sind definiert.", + "impl":"Verantwortlichkeiten und Eskalationswege sind definiert; {{ROLE_ISB}} koordiniert die Behandlung."}, + {"t":"S","req":"Erkenntnisse aus Vorfaellen werden ausgewertet (Lessons Learned) und fuehren zu Verbesserungen.", + "impl":"Nach relevanten Vorfaellen erfolgt eine Auswertung (Lessons Learned) mit Ableitung von Verbesserungen."}, + {"t":"S","req":"Meldepflichten (z. B. an Kunden/OEM, Behoerden) sind beruecksichtigt.", + "impl":"Bestehende Meldepflichten gegenueber Kunden/OEM und Behoerden werden im Behandlungsprozess beruecksichtigt."}, + ]}, + {"num":"1.6.3","title":"Krisenmanagement","reqs":[ + {"t":"M","req":"Die Organisation ist auf die Bewaeltigung von Krisensituationen vorbereitet (Rollen, Kommunikation, Entscheidungswege).", + "impl":"Ein Krisenmanagement mit Rollen, Kommunikations- und Entscheidungswegen ist definiert; der Krisenstab wird durch die {{ROLE_MANAGEMENT}} einberufen."}, + {"t":"S","req":"Krisen-/Notfallplaene werden regelmaessig geuebt und aktualisiert.", + "impl":"Krisen- und Notfallplaene werden mindestens {{REVIEW_CYCLE}} geuebt und aktualisiert."}, + ]}, + {"num":"5.2.8","title":"Kontinuitaetsplanung IT","reqs":[ + {"t":"M","req":"Fuer kritische IT-Dienste besteht eine Kontinuitaetsplanung (Wiederanlaufziele, Verantwortliche, Massnahmen).", + "impl":"Fuer kritische IT-Dienste bestehen Wiederanlaufziele, Verantwortliche und Massnahmen; {{ROLE_IT_LEAD}} verantwortet die Planung."}, + {"t":"S","req":"Wiederanlaufmassnahmen werden regelmaessig getestet; Ergebnisse werden dokumentiert.", + "impl":"Wiederanlaufmassnahmen werden mindestens {{REVIEW_CYCLE}} getestet; Ergebnisse werden dokumentiert."}, + ]}, + ]) + +pol(id="R05", fn="R05_Personalsicherheit-und-Awareness", + title="Personalsicherheit und Awareness", owner="ROLE_HR_LEAD", + purpose="Diese Richtlinie regelt Eignung und Qualifikation fuer sicherheitsrelevante Taetigkeiten, die vertragliche Verpflichtung des Personals sowie Schulung und Sensibilisierung.", + related=["R01","R06"], + roles=[("{{ROLE_HR_LEAD}}","Vertragliche Verpflichtung, Eignungspruefungen"), + ("{{ROLE_ISB}}","Inhalte und Nachweis von Schulung und Awareness"), + ("Fuehrungskraefte","Umsetzung im Verantwortungsbereich")], + controls=[ + {"num":"2.1.1","title":"Qualifikation fuer sensible Taetigkeiten","reqs":[ + {"t":"M","req":"Fuer sicherheitsrelevante/sensible Taetigkeiten ist die erforderliche Qualifikation und Zuverlaessigkeit der Beschaeftigten sichergestellt.", + "impl":"Fuer sensible Taetigkeiten werden Qualifikation und Zuverlaessigkeit im rechtlich zulaessigen Rahmen sichergestellt."}, + {"t":"S","req":"Anforderungen an Positionen sind beschrieben; angemessene Ueberpruefungen erfolgen im rechtlich zulaessigen Rahmen.", + "impl":"Sicherheitsanforderungen an Positionen sind beschrieben; Ueberpruefungen erfolgen anlassbezogen."}, + ]}, + {"num":"2.1.2","title":"Vertragliche Verpflichtung","reqs":[ + {"t":"M","req":"Alle Beschaeftigten sind vertraglich zur Einhaltung der Informationssicherheit und zur Vertraulichkeit verpflichtet.", + "impl":"Alle Beschaeftigten werden bei Eintritt vertraglich zur Vertraulichkeit und Einhaltung der Informationssicherheit verpflichtet."}, + {"t":"S","req":"Verpflichtungen gelten auch nach Beendigung des Arbeitsverhaeltnisses fort und umfassen Rueckgabepflichten.", + "impl":"Die Vertraulichkeitsverpflichtung gilt nachvertraglich fort; Rueckgabepflichten sind geregelt."}, + ]}, + {"num":"2.1.3","title":"Sensibilisierung und Schulung","reqs":[ + {"t":"M","req":"Beschaeftigte werden hinsichtlich Informationssicherheit sensibilisiert und geschult.", + "impl":"Beschaeftigte werden bei Eintritt und danach mindestens {{REVIEW_CYCLE}} geschult; Nachweise werden im ISMS-Tool ({{TOOL_NAME}}) gefuehrt."}, + {"t":"S","req":"Schulungsinhalte sind rollenspezifisch; die Wirksamkeit wird ueberprueft (z. B. Phishing-Tests).", + "impl":"Schulungen sind rollenspezifisch; die Wirksamkeit wird z. B. durch Phishing-Simulationen ueberprueft."}, + ]}, + ]) + +pol(id="R06", fn="R06_Mobiles-Arbeiten-und-mobile-Geraete", + title="Mobiles Arbeiten und mobile Geraete", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt mobiles Arbeiten (Homeoffice/Telearbeit) sowie den sicheren Umgang mit mobilen IT-Geraeten und Datentraegern.", + related=["R05","R07","R08"], + roles=[("{{ROLE_ISB}}","Festlegung der Sicherheitsanforderungen"), + ("{{ROLE_IT_LEAD}}","Technische Umsetzung (VPN, MDM)"), + ("Mitarbeitende","Einhaltung der Vorgaben")], + controls=[ + {"num":"2.1.4","title":"Mobiles Arbeiten","flag":"FLAG_MOBILE_WORK","reqs":[ + {"t":"M","req":"Mobiles Arbeiten ist geregelt (zulaessige Orte, Umgang mit Informationen, Absicherung der Verbindung).", + "impl":"Mobiles Arbeiten ist geregelt; der Zugriff erfolgt ueber gesicherte Verbindungen ({{TECH_VPN}}) und freigegebene Geraete."}, + {"t":"M","req":"Der Zugriff auf Unternehmensinformationen erfolgt ausschliesslich ueber gesicherte Verbindungen und freigegebene Geraete.", + "impl":"Der Zugriff auf Unternehmensinformationen ist auf freigegebene, abgesicherte Geraete beschraenkt."}, + {"t":"S","req":"Sichtschutz, Clean-Desk/Clean-Screen und Regeln fuer oeffentliche Umgebungen sind definiert.", + "impl":"Regeln zu Sichtschutz, Clean-Desk/Clean-Screen und zum Arbeiten in oeffentlichen Umgebungen sind definiert."}, + ]}, + {"num":"3.1.4","title":"Mobile Geraete und Datentraeger","flag":"FLAG_MOBILE_DEVICES","reqs":[ + {"t":"M","req":"Der Umgang mit mobilen IT-Geraeten und mobilen Datentraegern ist geregelt (Verschluesselung, Verlustmeldung, Freigabe).", + "impl":"Mobile Geraete sind verschluesselt und ueber {{TECH_MDM}} verwaltet; Verlustmeldung und Freigabe sind geregelt."}, + {"t":"M","req":"Mobile Geraete sind verschluesselt und koennen bei Verlust gesperrt/geloescht werden.", + "impl":"Bei Verlust koennen Geraete ueber {{TECH_MDM}} gesperrt und geloescht werden."}, + {"t":"S","req":"Der Einsatz privater Geraete (BYOD) ist geregelt oder untersagt; Wechseldatentraeger werden kontrolliert.", + "impl":"Der Einsatz privater Geraete ist geregelt; Wechseldatentraeger werden kontrolliert und nur verschluesselt zugelassen."}, + ]}, + ]) + +pol(id="R07", fn="R07_Physische-Sicherheit", + title="Physische Sicherheit", owner="ROLE_IT_LEAD", + purpose="Diese Richtlinie regelt den physischen Schutz von Informationen und informationsverarbeitenden Einrichtungen durch Sicherheitszonen, Zutrittsschutz und den Umgang mit unterstuetzenden Betriebsmitteln.", + related=["R02","R06"], + roles=[("{{ROLE_IT_LEAD}}","Zonenkonzept, Zutrittsschutz, Betriebsmittel"), + ("{{ROLE_ISB}}","Vorgabe der Anforderungen")], + controls=[ + {"num":"3.1.1","title":"Sicherheitszonen und Zutritt","reqs":[ + {"t":"M","req":"Sicherheitszonen sind definiert und der Zutritt zu schuetzenswerten Bereichen ist reglementiert und nachvollziehbar.", + "impl":"Sicherheitszonen sind definiert; der Zutritt zu schuetzenswerten Bereichen ist reglementiert und wird protokolliert."}, + {"t":"M","req":"Zutrittsrechte werden nach Bedarf vergeben, dokumentiert und bei Wegfall entzogen.", + "impl":"Zutrittsrechte werden bedarfsorientiert vergeben, dokumentiert und bei Wegfall entzogen."}, + {"t":"S","req":"Zutritte werden protokolliert; Besucher werden begleitet; technische Schutzmassnahmen sind vorhanden.", + "impl":"Besucher werden registriert und begleitet; technische Schutzmassnahmen (z. B. Alarm/Video im rechtlichen Rahmen) sind vorhanden."}, + ]}, + {"num":"3.1.3","title":"Umgang mit unterstuetzenden Betriebsmitteln","reqs":[ + {"t":"M","req":"Der Umgang mit unterstuetzenden Assets (z. B. Verkabelung, Strom-/Klimaversorgung, Serverraeume) ist geregelt und schuetzt vor Ausfall und unbefugtem Zugriff.", + "impl":"Serverraeume und Versorgungseinrichtungen sind zutrittsgeschuetzt und gegen Ausfall abgesichert."}, + {"t":"S","req":"Versorgungseinrichtungen werden gewartet und ueberwacht; Redundanzen bestehen fuer kritische Bereiche.", + "impl":"Versorgungseinrichtungen werden gewartet und ueberwacht; fuer kritische Bereiche bestehen Redundanzen (z. B. USV)."}, + ]}, + ]) + +pol(id="R08", fn="R08_Identitaets-und-Zugriffsmanagement", + title="Identitaets- und Zugriffsmanagement", owner="ROLE_IT_LEAD", + purpose="Diese Richtlinie regelt Identifikationsmittel, die sichere Anmeldung, die Verwaltung von Benutzerkonten und Anmeldeinformationen sowie die Vergabe und Kontrolle von Zugriffsrechten.", + related=["R02","R05","R10"], + roles=[("{{ROLE_IT_LEAD}}","Technische Umsetzung IAM"), + ("Fachbereiche","Fachliche Freigabe von Berechtigungen"), + ("{{ROLE_ISB}}","Ueberwachung der Einhaltung")], + controls=[ + {"num":"4.1.1","title":"Identifikationsmittel","reqs":[ + {"t":"M","req":"Der Einsatz von Identifikationsmitteln (Benutzerkennungen, Token, Zertifikate) ist geregelt und eindeutig personenbezogen.", + "impl":"Identifikationsmittel werden eindeutig personenbezogen vergeben; Sammelkonten werden vermieden."}, + {"t":"S","req":"Ausgabe, Ruecknahme und Sperrung von Identifikationsmitteln sind dokumentiert.", + "impl":"Ausgabe, Ruecknahme und Sperrung werden dokumentiert."}, + ]}, + {"num":"4.1.2","title":"Sichere Anmeldung","reqs":[ + {"t":"M","req":"Der Zugang zu IT-Diensten und IT-Systemen ist durch sichere Authentifizierungsverfahren geschuetzt.", + "impl":"Der Zugang ist durch sichere Authentifizierung geschuetzt; Passwortanforderungen sind zentral vorgegeben."}, + {"t":"M","req":"Fuer erhoehten Schutzbedarf und Fernzugriffe wird Mehr-Faktor-Authentifizierung (MFA) eingesetzt.", + "impl":"Fuer Fernzugriffe und erhoehten Schutzbedarf wird MFA ueber {{TECH_MFA}} durchgesetzt."}, + {"t":"S","req":"Passwortanforderungen, Sperrmechanismen und Sitzungsverwaltung sind definiert.", + "impl":"Passwortrichtlinie, Sperrmechanismen und Sitzungs-Timeouts sind zentral konfiguriert."}, + ]}, + {"num":"4.1.3","title":"Konten und Anmeldeinformationen","reqs":[ + {"t":"M","req":"Benutzerkonten und Anmeldeinformationen werden sicher verwaltet (Erstellung, Aenderung, Sperrung, Loeschung).", + "impl":"Konten werden ueber einen definierten Lebenszyklus (Joiner/Mover/Leaver) verwaltet."}, + {"t":"S","req":"Privilegierte und technische Konten werden gesondert verwaltet und ueberwacht.", + "impl":"Privilegierte und technische Konten werden gesondert verwaltet und ihre Nutzung ueberwacht."}, + ]}, + {"num":"4.2.1","title":"Zugriffsrechte","reqs":[ + {"t":"M","req":"Zugriffsrechte werden nach dem Minimalprinzip (need-to-know / least privilege) vergeben; Verfahren fuer Antrag, Pruefung und Genehmigung bestehen.", + "impl":"Zugriffsrechte werden nach dem Minimalprinzip vergeben; Antrag, Pruefung und Genehmigung erfolgen ueber ein definiertes Verfahren."}, + {"t":"M","req":"Zugriffsrechte werden bei Wegfall des Bedarfs entzogen und regelmaessig ueberprueft (Rezertifizierung){{IF_CUSTOMER}}.", + "impl":"Berechtigungen werden bei Wegfall entzogen und mindestens {{REVIEW_CYCLE}} rezertifiziert{{IF_CUSTOMER_IMPL}}."}, + {"t":"S","req":"Berechtigungen werden ueber Rollen vergeben; normale Konten erhalten keine privilegierten Rechte.", + "impl":"Berechtigungen werden rollenbasiert vergeben; Standardkonten erhalten keine privilegierten Rechte."}, + ]}, + ]) + +pol(id="R09", fn="R09_Kryptografie-und-Uebertragungsrichtlinie", + title="Kryptografie- und Uebertragungsrichtlinie", owner="ROLE_IT_LEAD", + purpose="Diese Richtlinie regelt den Einsatz kryptografischer Verfahren, die Schluesselverwaltung sowie den Schutz von Informationen bei der Uebertragung.", + related=["R08","R10","R12"], + roles=[("{{ROLE_IT_LEAD}}","Verfahren und Schluesselverwaltung"), + ("{{ROLE_ISB}}","Vorgabe zulaessiger Algorithmen/Staerken")], + controls=[ + {"num":"5.1.1","title":"Einsatz kryptografischer Verfahren","reqs":[ + {"t":"M","req":"Der Einsatz von Kryptografie ist geregelt; zulaessige Verfahren und Schluessellaengen entsprechen dem Stand der Technik.", + "impl":"Zulaessige Verfahren und Schluessellaengen entsprechen dem Stand der Technik ({{TECH_CRYPTO}}) und sind vorgegeben."}, + {"t":"M","req":"Schluessel werden ueber ihren gesamten Lebenszyklus sicher verwaltet.", + "impl":"Schluessel werden ueber ihren Lebenszyklus (Erzeugung, Verteilung, Speicherung, Sperrung, Vernichtung) sicher verwaltet."}, + {"t":"S","req":"Ein Kryptokonzept ist dokumentiert{{IF_PKI}}.", + "impl":"Ein Kryptokonzept ist dokumentiert{{IF_PKI_IMPL}}."}, + ]}, + {"num":"5.1.2","title":"Schutz bei Uebertragung","reqs":[ + {"t":"M","req":"Informationen werden abhaengig vom Schutzbedarf bei der Uebertragung geschuetzt (z. B. Transportverschluesselung, gesicherte Kanaele).", + "impl":"Informationen werden schutzbedarfsgerecht per Transportverschluesselung (z. B. TLS) und gesicherte Kanaele geschuetzt."}, + {"t":"S","req":"Regeln fuer sichere Uebertragungswege (E-Mail-Verschluesselung, sichere Dateiuebertragung) sind definiert.", + "impl":"Regeln fuer E-Mail-Verschluesselung und sichere Dateiuebertragung sind definiert."}, + ]}, + ]) + +pol(id="R10", fn="R10_Betriebssicherheit", + title="Betriebssicherheit", owner="ROLE_IT_LEAD", + purpose="Diese Richtlinie regelt den sicheren IT-Betrieb: Change-Management, Trennung von Umgebungen, Malware-Schutz, Protokollierung, Schwachstellen- und Patch-Management, technische Pruefungen, Netzwerksicherheit sowie Datensicherung und Wiederherstellung.", + related=["R04","R08","R11"], + roles=[("{{ROLE_IT_LEAD}}","Sicherer IT-Betrieb"), + ("{{ROLE_ISB}}","Ueberwachung der Einhaltung")], + controls=[ + {"num":"5.2.1","title":"Change-Management","reqs":[ + {"t":"M","req":"Aenderungen an IT-Systemen werden geregelt beantragt, bewertet, getestet, genehmigt und dokumentiert.", + "impl":"Aenderungen durchlaufen ein Change-Verfahren mit Bewertung, Test, Genehmigung und Dokumentation."}]}, + {"num":"5.2.2","title":"Trennung der Umgebungen","reqs":[ + {"t":"M","req":"Entwicklungs-, Test- und Produktionsumgebungen sind getrennt.", + "impl":"Entwicklung, Test und Produktion sind getrennt betrieben."}, + {"t":"S","req":"Produktivdaten werden nicht ungeschuetzt in Test-/Entwicklungsumgebungen verwendet.", + "impl":"Produktivdaten werden in Test-/Entwicklungsumgebungen nur anonymisiert/pseudonymisiert genutzt."}]}, + {"num":"5.2.3","title":"Schutz vor Malware","reqs":[ + {"t":"M","req":"Anforderungen zum Schutz vor Schadsoftware sind bestimmt; technische und organisatorische Massnahmen sind umgesetzt.", + "impl":"Malware-Schutz ist ueber {{TECH_MALWARE}} auf allen relevanten Systemen umgesetzt."}, + {"t":"S","req":"Schutzsoftware wird automatisch aktualisiert; unnoetige Netzwerkdienste sind deaktiviert.", + "impl":"Schutzsoftware aktualisiert sich automatisch; unnoetige Netzwerkdienste sind deaktiviert."}]}, + {"num":"5.2.4","title":"Protokollierung und Auswertung","reqs":[ + {"t":"M","req":"Sicherheitsrelevante Ereignisse werden protokolliert und ausgewertet.", + "impl":"Sicherheitsrelevante Ereignisse werden protokolliert und ueber {{TECH_SIEM}} ausgewertet."}, + {"t":"S","req":"Protokolle sind vor Manipulation geschuetzt; Aufbewahrungsfristen sind definiert.", + "impl":"Protokolle sind manipulationsgeschuetzt; Aufbewahrungsfristen sind definiert."}]}, + {"num":"5.2.5","title":"Schwachstellen- und Patch-Management","reqs":[ + {"t":"M","req":"Schwachstellen werden identifiziert und risikoorientiert behoben (Patch-Management).", + "impl":"Schwachstellen werden erfasst und risikoorientiert gepatcht; kritische Patches werden priorisiert."}, + {"t":"S","req":"Es besteht ein regelmaessiges Schwachstellen-Scanning; kritische Patches werden priorisiert.", + "impl":"Ein regelmaessiges Schwachstellen-Scanning ist etabliert."}]}, + {"num":"5.2.6","title":"Technische Ueberpruefung","reqs":[ + {"t":"M","req":"IT-Systeme und Dienste werden technisch ueberprueft (z. B. Systemhaertung, Penetrationstests).", + "impl":"Systeme werden gehaertet und risikoorientiert technisch geprueft (z. B. Penetrationstests)."}]}, + {"num":"5.2.7","title":"Netzwerksicherheit","reqs":[ + {"t":"M","req":"Das Netzwerk wird gesteuert und abgesichert (Segmentierung, Zugangskontrolle, Absicherung nach aussen).", + "impl":"Das Netzwerk ist segmentiert, zugangskontrolliert und nach aussen abgesichert (Firewall)."}, + {"t":"M","req":"{{IF_OT}}Produktions-/OT-Netze sind von Office-Netzen getrennt und besonders abgesichert.", + "impl":"{{IF_OT}}Produktions-/OT-Netze sind von Office-Netzen getrennt und besonders abgesichert.","cond":"FLAG_OT_USED"}, + {"t":"S","req":"Ein aktueller Netzplan und ein Segmentierungskonzept liegen vor.", + "impl":"Ein aktueller Netzplan und ein Segmentierungskonzept werden gepflegt."}]}, + {"num":"5.2.9","title":"Backup und Wiederherstellung","reqs":[ + {"t":"M","req":"Daten und IT-Dienste werden gesichert; Wiederherstellung ist geregelt.", + "impl":"Daten und Dienste werden ueber {{TECH_BACKUP}} gesichert; die Wiederherstellung ist geregelt."}, + {"t":"M","req":"Wiederherstellungstests werden regelmaessig durchgefuehrt.", + "impl":"Wiederherstellungstests werden mindestens {{REVIEW_CYCLE}} durchgefuehrt und dokumentiert."}, + {"t":"S","req":"Backups werden geschuetzt/ausgelagert aufbewahrt (z. B. offline/immutable).", + "impl":"Backups werden geschuetzt und ausgelagert (offline/immutable) aufbewahrt."}]}, + ]) + +pol(id="R11", fn="R11_Sichere-Systembeschaffung-und-Entwicklung", + title="Sichere Systembeschaffung und Entwicklung", owner="ROLE_IT_LEAD", + purpose="Diese Richtlinie regelt die Beruecksichtigung der Informationssicherheit bei Beschaffung und Weiterentwicklung von IT-Systemen, Anforderungen an Netzdienste sowie Rueckgabe und sichere Loeschung von Informationen.", + related=["R02","R10","R12"], + roles=[("{{ROLE_IT_LEAD}}","Beschaffung/Entwicklung"), + ("{{ROLE_ISB}}","Definition Sicherheitsanforderungen")], + controls=[ + {"num":"5.3.1","title":"Sicherheit bei Beschaffung/Entwicklung","reqs":[ + {"t":"M","req":"Bei Beschaffung oder Weiterentwicklung von IT-Systemen werden Informationssicherheitsanforderungen ermittelt und beruecksichtigt.", + "impl":"Sicherheitsanforderungen sind fester Bestandteil von Beschaffungs- und Aenderungsprozessen (Security by Design)."}, + {"t":"M","req":"{{IF_DEV}}Fuer die Eigenentwicklung gelten Vorgaben fuer sichere Entwicklung (Secure Coding, Tests, Freigaben).", + "impl":"{{IF_DEV}}Fuer die Eigenentwicklung gelten Secure-Coding-Vorgaben mit Tests und Freigaben.","cond":"FLAG_DEV_INHOUSE"}, + {"t":"S","req":"Sicherheitsanforderungen sind Bestandteil des Beschaffungs-/Entwicklungsprozesses (Security by Design).", + "impl":"Sicherheitsanforderungen werden dokumentiert und ihre Umsetzung vor Freigabe geprueft."}]}, + {"num":"5.3.2","title":"Anforderungen an Netzdienste","reqs":[ + {"t":"M","req":"Sicherheitsanforderungen an Netzdienste (intern und extern) sind definiert.", + "impl":"Fuer genutzte Netzdienste sind Sicherheitsanforderungen definiert und vereinbart."}]}, + {"num":"5.3.3","title":"Rueckgabe und sichere Loeschung","reqs":[ + {"t":"M","req":"Rueckgabe und sichere Entfernung/Loeschung von Informationen und Assets sind geregelt.", + "impl":"Rueckgabe und sichere Loeschung (bei Vertragsende, Geraeteausmusterung) sind geregelt und werden nachgewiesen."}, + {"t":"S","req":"Loeschverfahren entsprechen dem Schutzbedarf; Loeschungen werden nachgewiesen.", + "impl":"Loeschverfahren richten sich nach dem Schutzbedarf; Loeschungen werden dokumentiert."}]}, + ]) + +pol(id="R12", fn="R12_Cloud-KI-und-externe-IT-Dienste", + title="Cloud-, KI- und externe IT-Dienste", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt den Schutz von Informationen bei der Nutzung ausgelagerter oder geteilter externer IT-Dienste (Cloud) sowie beim Einsatz von KI-/GenAI-Diensten, einschliesslich Auswahl, Freigabe, zulaessiger Nutzung und Datenpreisgabe.", + related=["R09","R11","R13"], + roles=[("{{ROLE_ISB}}","Freigabe Cloud-/KI-Dienste, Pflege der Freigabeliste"), + ("{{ROLE_IT_LEAD}}","Technische Absicherung"), + ("Fachbereiche","Nutzung nur freigegebener Dienste")], + controls=[ + {"num":"5.3.4","title":"Externe/geteilte IT-Dienste und Cloud","reqs":[ + {"t":"M","req":"Bei geteilten externen IT-Diensten ist durch wirksame Mandantentrennung sichergestellt, dass Unbefugte anderer Organisationen nicht auf eigene Informationen zugreifen koennen.", + "impl":"Bei geteilten Diensten wird auf eine wirksame Mandantentrennung geachtet und diese vertraglich zugesichert."}, + {"t":"M","req":"{{IF_CLOUD}}Cloud-Dienste werden vor Nutzung bewertet und freigegeben; nur freigegebene Dienste werden fuer Unternehmensinformationen genutzt.", + "impl":"{{IF_CLOUD}}Cloud-Dienste werden vor Nutzung bewertet (Schutzbedarf, Datenlokation, Exit) und freigegeben; die Freigabeliste wird im ISMS-Tool ({{TOOL_NAME}}) gepflegt.","cond":"FLAG_CLOUD_USED"}, + {"t":"S","req":"Das Segregationskonzept des Anbieters ist dokumentiert und wird bei Aenderungen angepasst.", + "impl":"Das Segregationskonzept des Anbieters wird dokumentiert und bei Aenderungen aktualisiert."}]}, + {"num":"5.3.4-KI","title":"Nutzung von KI-/GenAI-Diensten","flag":"FLAG_AI_USED","reqs":[ + {"t":"M","req":"Der Einsatz von KI-/GenAI-Diensten ist geregelt; es werden nur freigegebene Dienste genutzt.", + "impl":"Der Einsatz von KI-/GenAI-Diensten ist geregelt; nur freigegebene Dienste (Freigabeliste im ISMS-Tool) duerfen genutzt werden."}, + {"t":"M","req":"Die Eingabe vertraulicher oder personenbezogener Informationen in nicht freigegebene KI-Dienste ist untersagt; zulaessige Datenklassen je Dienst sind definiert.", + "impl":"Zulaessige Datenklassen je KI-Dienst sind definiert; die Eingabe vertraulicher/personenbezogener Daten in nicht freigegebene Dienste ist untersagt."}, + {"t":"M","req":"Bei freigegebenen KI-Diensten ist geklaert, ob Eingaben zum Training genutzt werden; eine Trainings-/Weitergabe von Unternehmensdaten wird ausgeschlossen oder vertraglich untersagt.", + "impl":"Bei Freigabe wird geprueft und vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden."}, + {"t":"S","req":"Ergebnisse werden vor geschaeftskritischer Verwendung geprueft (Human-in-the-Loop); der KI-Einsatz wird dokumentiert; regulatorische Anforderungen (z. B. EU AI Act) werden beruecksichtigt.", + "impl":"KI-Ergebnisse werden vor kritischer Verwendung durch Menschen geprueft; der KI-Einsatz wird dokumentiert und regulatorische Anforderungen (EU AI Act) beruecksichtigt."}]}, + ]) + +pol(id="R13", fn="R13_Lieferanten-und-Dienstleistersteuerung", + title="Lieferanten- und Dienstleistersteuerung", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt die Sicherstellung der Informationssicherheit bei Auftragnehmern und Lieferanten, Vertraulichkeitsvereinbarungen sowie die Abgrenzung von Verantwortlichkeiten mit externen IT-Dienstleistern.", + related=["R01","R12"], + roles=[("{{ROLE_ISB}}","Steuerung der Lieferantensicherheit, Pflege Lieferantenverzeichnis"), + ("Einkauf","Vertragliche Einbindung der Anforderungen")], + controls=[ + {"num":"6.1.1","title":"Informationssicherheit bei Lieferanten","reqs":[ + {"t":"M","req":"Informationssicherheitsanforderungen an Auftragnehmer/Lieferanten sind ermittelt und werden vertraglich vereinbart und ueberwacht.", + "impl":"Sicherheitsanforderungen an Lieferanten werden ermittelt, vertraglich vereinbart und ueberwacht; das Lieferantenverzeichnis wird im ISMS-Tool ({{TOOL_NAME}}) gepflegt."}, + {"t":"M","req":"Lieferanten werden risikoorientiert bewertet.", + "impl":"Lieferanten werden risikoorientiert (nach Schutzbedarf und Zugriff) bewertet."}, + {"t":"S","req":"Die Einhaltung der Anforderungen wird regelmaessig ueberprueft (z. B. Nachweise, Audits, TISAX-Label).", + "impl":"Die Einhaltung wird regelmaessig ueberprueft (Nachweise, Audits, TISAX-Label)."}]}, + {"num":"6.1.2","title":"Vertraulichkeit","reqs":[ + {"t":"M","req":"Der Austausch von Informationen mit Externen ist durch Vertraulichkeitsvereinbarungen (NDA) abgesichert.", + "impl":"Vor dem Austausch schutzbeduerftiger Informationen werden NDAs abgeschlossen."}, + {"t":"S","req":"NDA-Vorlagen sind standardisiert; Geltungsdauer und Rueckgabe-/Loeschpflichten sind geregelt.", + "impl":"Standardisierte NDA-Vorlagen mit Geltungsdauer und Rueckgabe-/Loeschpflichten werden verwendet."}]}, + {"num":"6.1.3","title":"Abgrenzung der Verantwortlichkeiten","reqs":[ + {"t":"M","req":"{{IF_EXTIT}}Verantwortlichkeiten zwischen der Organisation und externen IT-Dienstleistern sind klar abgegrenzt und dokumentiert.", + "impl":"{{IF_EXTIT}}Die Verantwortlichkeiten mit externen IT-Dienstleistern (Betriebs-, Sicherheits-, Meldepflichten) sind abgegrenzt und dokumentiert.","cond":"FLAG_EXTERNAL_IT"}, + {"t":"S","req":"Schnittstellen, Eskalations- und Meldewege mit Dienstleistern sind vereinbart.", + "impl":"Schnittstellen sowie Eskalations- und Meldewege sind vertraglich vereinbart."}]}, + ]) + +pol(id="R14", fn="R14_Compliance-und-Datenschutz", + title="Compliance und Datenschutz", owner="ROLE_ISB", + purpose="Diese Richtlinie regelt die Einhaltung regulatorischer und vertraglicher Vorgaben sowie den Schutz personenbezogener Daten.", + related=["L00","R03"], + roles=[("{{ROLE_ISB}}","Compliance-Register"), + ("{{ROLE_DPO}}","Datenschutz")], + controls=[ + {"num":"7.1.1","title":"Regulatorische und vertragliche Compliance","reqs":[ + {"t":"M","req":"Relevante gesetzliche, regulatorische und vertragliche Anforderungen an die Informationssicherheit sind identifiziert, dokumentiert und werden eingehalten.", + "impl":"Relevante Anforderungen werden in einem Compliance-/Rechtsregister im ISMS-Tool ({{TOOL_NAME}}) erfasst und ihre Einhaltung nachverfolgt."}, + {"t":"S","req":"Ein Compliance-/Rechtsregister wird gepflegt und regelmaessig aktualisiert; Verantwortliche sind benannt.", + "impl":"Das Register wird mindestens {{REVIEW_CYCLE}} aktualisiert; Verantwortliche sind benannt."}]}, + {"num":"7.1.2","title":"Schutz personenbezogener Daten","flag":"FLAG_PERSONAL_DATA","reqs":[ + {"t":"M","req":"Beim Umgang mit personenbezogenen Daten werden die datenschutzrechtlichen Anforderungen (z. B. DSGVO) beruecksichtigt.", + "impl":"Datenschutzrechtliche Anforderungen (DSGVO) werden beruecksichtigt; {{ROLE_DPO}} ist eingebunden."}, + {"t":"M","req":"Ein Verzeichnis der Verarbeitungstaetigkeiten wird gefuehrt.", + "impl":"Das Verzeichnis der Verarbeitungstaetigkeiten wird im ISMS-Tool ({{TOOL_NAME}}) gefuehrt."}, + {"t":"S","req":"Technische und organisatorische Massnahmen (TOM), Loeschkonzepte und Betroffenenrechte sind geregelt.", + "impl":"TOM, Loeschkonzepte und Prozesse fuer Betroffenenrechte sind geregelt."}]}, + ]) + +# --------------------------------------------------------------------------- +# Inline-Bedingungsersetzungen (Feature-Flags in Req/Impl-Text) +# --------------------------------------------------------------------------- +INLINE = { + "{{IF_CUSTOMER}}":"{{#if FLAG_CUSTOMER_SYSTEMS}}, auch fuer Zugriffe in Kundensystemen{{/if}}", + "{{IF_CUSTOMER_IMPL}}":"{{#if FLAG_CUSTOMER_SYSTEMS}}, auch fuer Zugriffe in Kundensystemen{{/if}}", + "{{IF_PKI}}":"{{#if FLAG_CRYPTO_PKI}} und eine PKI/Zertifikatsverwaltung ist etabliert{{/if}}", + "{{IF_PKI_IMPL}}":"{{#if FLAG_CRYPTO_PKI}}; eine PKI/Zertifikatsverwaltung ist etabliert{{/if}}", + "{{IF_OT}}":"", "{{IF_DEV}}":"", "{{IF_CLOUD}}":"", "{{IF_EXTIT}}":"", +} +def inline(s): + for k,v in INLINE.items(): s=s.replace(k,v) + return s + +# --------------------------------------------------------------------------- +# Rendering +# --------------------------------------------------------------------------- +META = """# Richtlinie {title} + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{{{ISMS_SCOPE}}}} | +| Organisation | {{{{ORG_NAME}}}} | +| Verantwortlich | {{{{{owner}}}}} | +| Freigabe durch | {{{{ROLE_MANAGEMENT}}}} | +| Version | {{{{DOC_VERSION}}}} | +| Datum | {{{{DOC_DATE}}}} | +| Status | {{{{DOC_STATUS}}}} | +""" + +mapping = {"meta":{"paket":"ISMS-Vorlagenpaket v2","standard":"VDA ISA 2027 (Information Security)"},"anforderungen":[]} + +def suffix(reqs): + m=s=0; ids=[] + for r in reqs: + if r["t"]=="M": m+=1; ids.append("M%d"%m) + else: s+=1; ids.append("S%d"%s) + return ids + +for p in POLICIES: + ids_by_control={} + body=[META.format(title=p["title"], owner=p["owner"])] + body.append("\n## 1. Zweck\n\n"+inline(p["purpose"])+" Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfuellung der Anforderungen des VDA ISA 2027.\n") + body.append("## 2. Geltungsbereich\n\nDiese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}).\n") + body.append("## 3. Anforderungen und Umsetzung\n\n> Aufbau je Abschnitt: **Anforderung** (normativ, aus VDA ISA; [MUSS]/[SOLL]) und **Umsetzung bei {{ORG_NAME}}** (tatsaechliche Ausgestaltung, anzupassen wo erforderlich).\n") + sec=0 + for c in p["controls"]: + sec+=1 + ids=suffix(c["reqs"]) + head=f"### 3.{sec} {c['title']} (ISA {c['num']})\n" + wrap_flag=c.get("flag") + block=[head, "\n**Anforderung**\n"] + for r,rid in zip(c["reqs"], ids): + full_id=f"{c['num']}-{rid}" + tag="[MUSS]" if r["t"]=="M" else "[SOLL]" + line=f"\n- **{tag}** {inline(r['req'])}" + cond = r.get("cond") + if r["t"]=="S" and not cond: cond="FLAG_INCLUDE_SHOULD" + if cond: line=f"{{{{#if {cond}}}}}\n{line}\n{{{{/if}}}}" + block.append(line) + block.append("\n**Umsetzung bei {{ORG_NAME}}**\n") + for r,rid in zip(c["reqs"], ids): + full_id=f"{c['num']}-{rid}" + line=f"\n{inline(r['impl'])}" + cond = r.get("cond") + if r["t"]=="S" and not cond: cond="FLAG_INCLUDE_SHOULD" + if cond: line=f"{{{{#if {cond}}}}}\n{line}\n{{{{/if}}}}" + block.append(line) + # mapping-Eintrag + mapping["anforderungen"].append({ + "id":full_id,"policy":p["id"],"policy_file":p["fn"]+".md", + "control":c["num"],"type":"MUSS" if r["t"]=="M" else "SOLL", + "req_anchor":f"REQ {full_id}","impl_anchor":f"IMPL {full_id}", + "condition": r.get("cond") or (None if r["t"]=="M" else "FLAG_INCLUDE_SHOULD"), + "requirement": inline(r["req"]).replace("{{IF_OT}}","").replace("{{IF_DEV}}","").replace("{{IF_CLOUD}}","").replace("{{IF_EXTIT}}",""), + "implementation": inline(r["impl"]).replace("{{IF_OT}}","").replace("{{IF_DEV}}","").replace("{{IF_CLOUD}}","").replace("{{IF_EXTIT}}",""), + "link":f"{{{{LINK:{p['id']}#{c['num']}}}}}", + "nachweis_link":"{{LINK:NACHWEISREGISTER}}" + }) + section_text="\n".join(block) + if wrap_flag: + section_text=f"{{{{#if {wrap_flag}}}}}\n{section_text}\n{{{{/if}}}}" + body.append(section_text+"\n") + # Verbindlichkeit / Rollen / Pruefung / Nachweise / Verwandte + body.append("## 4. Verbindlichkeit\n\nDiese Richtlinie ist fuer alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{"+p["owner"]+"}} ueberwacht.\n") + roles="\n".join("| %s | %s |"%(r,v) for r,v in p["roles"]) + body.append("## 5. Rollen und Verantwortlichkeiten\n\n| Rolle | Verantwortung in dieser Richtlinie |\n|-------|-------------------------------------|\n"+roles+"\n") + body.append("## 6. Ueberpruefung und Aktualisierung\n\nDiese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{"+p["owner"]+"}} ueberprueft und durch {{ROLE_MANAGEMENT}} freigegeben.\n") + body.append("## 7. Nachweise\n\nDie Nachweise zur Umsetzung dieser Richtlinie werden nicht in diesem Dokument gefuehrt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehoerigen Eintraegen des ISMS-Tools ({{TOOL_NAME}}).\n") + rel=", ".join("{{LINK:%s}}"%x for x in p["related"]) + body.append("## 8. Verwandte Dokumente\n\n- Informationssicherheitsleitlinie: {{LINK:L00}}\n- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}}\n- Nachweisregister: {{LINK:NACHWEISREGISTER}}\n- Weitere: "+rel+"\n\n\n") + txt="\n".join(body) + with open(os.path.join(RDIR,p["fn"]+".md"),"w",encoding="utf-8") as f: + f.write(txt) + +json.dump(mapping, open(os.path.join(BASE,"mapping.json"),"w",encoding="utf-8"), ensure_ascii=False, indent=1) +print("Richtlinien:", len(POLICIES), "| Mapping-Eintraege:", len(mapping["anforderungen"])) diff --git a/seed/isms-vorlagenpaket-v2/_generate_v3.py b/seed/isms-vorlagenpaket-v2/_generate_v3.py new file mode 100644 index 0000000..fd10eaf --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_generate_v3.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +"""Generator v3: Richtlinien R01-R14 mit VOLLSTAENDIGEN ISA-Anforderungen +(must/should/high/vhigh, 1:1), Schutzbedarf-Flags, gebuendelte Umsetzung, Mapping, Matrix.""" +import os, json, importlib.util, collections +BASE=os.path.dirname(__file__) +RDIR=os.path.join(BASE,"richtlinien") + +spec=importlib.util.spec_from_file_location("isa_de", os.path.join(BASE,"_isa_de.py")) +m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m) +DATA=m.DATA; CUSTOM=m.CUSTOM + +POLICY_META={ + "R01":dict(title="ISMS-Organisation und Rollen", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt Aufbau, Steuerung und Verantwortlichkeiten des ISMS der {{ORG_NAME}} sowie die Berücksichtigung der Informationssicherheit in Projekten.", + roles=[("{{ROLE_MANAGEMENT}}","Beauftragung, Gesamtverantwortung, Managementbewertung"),("{{ROLE_ISB}}","Operative Steuerung des ISMS"),("{{ROLE_IT_LEAD}}","Technische Umsetzung")], related=["L00","R03","R13"]), + "R02":dict(title="Asset- und Klassifizierungsrichtlinie", owner="{{ROLE_IT_LEAD}}", + purpose="Diese Richtlinie regelt Identifikation, Klassifizierung und geschützten Umgang mit Informationswerten sowie die Zulassung von Hard- und Software.", + roles=[("{{ROLE_IT_LEAD}}","Asset-Inventar, Zulassung Hard-/Software"),("{{ROLE_ISB}}","Klassifizierungsschema"),("Asset Owner","Pflege einzelner Assets")], related=["R01","R08","R11"]), + "R03":dict(title="Risikomanagement- und Auditrichtlinie", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt Identifikation, Bewertung und Behandlung von Informationssicherheitsrisiken sowie interne und unabhängige Überprüfungen.", + roles=[("{{ROLE_ISB}}","Risikomanagement, Audits"),("{{ROLE_MANAGEMENT}}","Risikoakzeptanz")], related=["R01","R04"]), + "R04":dict(title="Incident-, Notfall- und Kontinuitätsrichtlinie", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt Meldung und Behandlung von Sicherheitsereignissen, Krisenmanagement sowie Notfall- und Kontinuitätsplanung.", + roles=[("{{ROLE_ISB}}","Vorfallskoordination"),("{{ROLE_IT_LEAD}}","Notfall-/Wiederanlaufplanung"),("{{ROLE_MANAGEMENT}}","Krisenstab")], related=["R03","R10"]), + "R05":dict(title="Personalsicherheit und Awareness", owner="{{ROLE_HR_LEAD}}", + purpose="Diese Richtlinie regelt Eignung, vertragliche Verpflichtung sowie Schulung und Sensibilisierung des Personals.", + roles=[("{{ROLE_HR_LEAD}}","Verpflichtung, Eignung"),("{{ROLE_ISB}}","Awareness/Schulung")], related=["R01","R06"]), + "R06":dict(title="Mobiles Arbeiten und mobile Geräte", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt mobiles Arbeiten sowie den Umgang mit mobilen IT-Geräten und Datenträgern.", + roles=[("{{ROLE_ISB}}","Sicherheitsanforderungen"),("{{ROLE_IT_LEAD}}","Technische Umsetzung")], related=["R05","R07","R08"]), + "R07":dict(title="Physische Sicherheit", owner="{{ROLE_IT_LEAD}}", + purpose="Diese Richtlinie regelt physischen Schutz durch Sicherheitszonen, Zutrittsschutz und den Umgang mit unterstützenden Betriebsmitteln.", + roles=[("{{ROLE_IT_LEAD}}","Zonen, Zutritt, Betriebsmittel"),("{{ROLE_ISB}}","Vorgaben")], related=["R02","R06"]), + "R08":dict(title="Identitäts- und Zugriffsmanagement", owner="{{ROLE_IT_LEAD}}", + purpose="Diese Richtlinie regelt Identifikationsmittel, sichere Anmeldung, Kontenverwaltung sowie Vergabe und Kontrolle von Zugriffsrechten.", + roles=[("{{ROLE_IT_LEAD}}","Technische Umsetzung IAM"),("Fachbereiche","Freigabe von Berechtigungen"),("{{ROLE_ISB}}","Überwachung")], related=["R02","R05","R10"]), + "R09":dict(title="Kryptografie- und Übertragungsrichtlinie", owner="{{ROLE_IT_LEAD}}", + purpose="Diese Richtlinie regelt kryptografische Verfahren, Schlüsselverwaltung und Schutz bei der Informationsübertragung.", + roles=[("{{ROLE_IT_LEAD}}","Verfahren/Schlüssel"),("{{ROLE_ISB}}","Zulässige Algorithmen")], related=["R08","R10","R12"]), + "R10":dict(title="Betriebssicherheit", owner="{{ROLE_IT_LEAD}}", + purpose="Diese Richtlinie regelt den sicheren IT-Betrieb: Change, Umgebungstrennung, Malware-Schutz, Protokollierung, Schwachstellen, technische Prüfung, Netzwerksicherheit sowie Datensicherung.", + roles=[("{{ROLE_IT_LEAD}}","Sicherer IT-Betrieb"),("{{ROLE_ISB}}","Überwachung")], related=["R04","R08","R11"]), + "R11":dict(title="Sichere Systembeschaffung und Entwicklung", owner="{{ROLE_IT_LEAD}}", + purpose="Diese Richtlinie regelt Informationssicherheit bei Beschaffung und Entwicklung, Anforderungen an Netzdienste sowie Rückgabe und sichere Löschung.", + roles=[("{{ROLE_IT_LEAD}}","Beschaffung/Entwicklung"),("{{ROLE_ISB}}","Sicherheitsanforderungen")], related=["R02","R10","R12"]), + "R12":dict(title="Cloud-, KI- und externe IT-Dienste", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt den Schutz in ausgelagerten/geteilten externen IT-Diensten (Cloud) sowie beim Einsatz von KI-/GenAI-Diensten.", + roles=[("{{ROLE_ISB}}","Freigabe/Steuerung"),("{{ROLE_IT_LEAD}}","Technische Absicherung"),("Fachbereiche","Nutzung freigegebener Dienste")], related=["R09","R11","R13"]), + "R13":dict(title="Lieferanten- und Dienstleistersteuerung", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt Sicherstellung der Informationssicherheit bei Lieferanten, Vertraulichkeitsvereinbarungen und Abgrenzung der Verantwortlichkeiten.", + roles=[("{{ROLE_ISB}}","Lieferantensteuerung"),("Einkauf","Vertragliche Einbindung")], related=["R01","R12"]), + "R14":dict(title="Compliance und Datenschutz", owner="{{ROLE_ISB}}", + purpose="Diese Richtlinie regelt die Einhaltung regulatorischer/vertraglicher Vorgaben sowie den Schutz personenbezogener Daten.", + roles=[("{{ROLE_ISB}}","Compliance-Register"),("{{ROLE_DPO}}","Datenschutz")], related=["L00","R03"]), +} + +TAG={"must":"[MUSS]","should":"[SOLL]","high":"[HOCH]","vhigh":"[SEHR HOCH]"} +LETTER={"must":"M","should":"S","high":"H","vhigh":"V"} +COND={"must":None,"should":"FLAG_INCLUDE_SHOULD","high":"FLAG_HIGH_PROTECTION","vhigh":"FLAG_VERY_HIGH_PROTECTION"} + +# Reihenfolge der Controls je Policy aus DATA-Insertionsreihenfolge (L00 raus, CUSTOM ans Ende der jeweiligen Policy) +order_by_pol=collections.OrderedDict() +for ctrl,d in DATA.items(): + if d["policy"]=="L00": continue + order_by_pol.setdefault(d["policy"],[]).append((ctrl,d,True)) +for ctrl,d in CUSTOM.items(): + order_by_pol.setdefault(d["policy"],[]).append((ctrl,d,False)) + +mapping={"meta":{"paket":"ISMS-Vorlagenpaket v2","standard":"VDA ISA 2027 (Information Security)", + "hinweis":"Anforderungen 1:1 aus ISA; Umsetzung gebuendelt je Control. is_isa=false = kundenspezifische Ergaenzung (z.B. KI)."}, + "anforderungen":[]} + +def render_reqs(ctrl, d): + """liefert (anforderung_block, impl_block, mapping_entries)""" + entries=[]; lines_req=[]; + for lvl in ["must","should","high","vhigh"]: + items=d.get(lvl,[]) or [] + cnt=0 + for text in items: + cnt+=1 + rid=f"{ctrl}-{LETTER[lvl]}{cnt}" + block=f"\n- **{TAG[lvl]}** {text}" + if COND[lvl]: + block=f"{{{{#if {COND[lvl]}}}}}\n{block}\n{{{{/if}}}}" + lines_req.append(block) + has_elev=bool(d.get("impl_elev")) + impl_anchor = f"IMPL {ctrl}-elev" if (lvl in ("high","vhigh") and has_elev) else f"IMPL {ctrl}" + entries.append({"id":rid,"policy":d["policy"],"control":ctrl,"level":lvl, + "type":{"must":"MUSS","should":"SOLL","high":"HOCH","vhigh":"SEHR HOCH"}[lvl], + "is_isa": ctrl in DATA, + "req_anchor":f"REQ {rid}","impl_anchor":impl_anchor,"condition":COND[lvl], + "requirement":text, + "link":f"{{{{LINK:{d['policy']}#{ctrl}}}}}","nachweis_link":"{{LINK:NACHWEISREGISTER}}"}) + # Umsetzung + impl=[f"\n{d['impl']}"] + if d.get("impl_elev"): + impl.append(f"{{{{#if FLAG_ELEVATED_PROTECTION}}}}\n\n{d['impl_elev']}\n{{{{/if}}}}") + return "\n".join(lines_req), "\n\n".join(impl), entries + +META_HEAD="""# Richtlinie {title} + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{{{ISMS_SCOPE}}}} | +| Organisation | {{{{ORG_NAME}}}} | +| Verantwortlich | {owner} | +| Freigabe durch | {{{{ROLE_MANAGEMENT}}}} | +| Version | {{{{DOC_VERSION}}}} | +| Datum | {{{{DOC_DATE}}}} | +| Status | {{{{DOC_STATUS}}}} | +""" + +FN={"R01":"R01_ISMS-Organisation-und-Rollen","R02":"R02_Asset-und-Klassifizierungsrichtlinie", + "R03":"R03_Risikomanagement-und-Auditrichtlinie","R04":"R04_Incident-Notfall-und-Kontinuitaetsrichtlinie", + "R05":"R05_Personalsicherheit-und-Awareness","R06":"R06_Mobiles-Arbeiten-und-mobile-Geraete", + "R07":"R07_Physische-Sicherheit","R08":"R08_Identitaets-und-Zugriffsmanagement", + "R09":"R09_Kryptografie-und-Uebertragungsrichtlinie","R10":"R10_Betriebssicherheit", + "R11":"R11_Sichere-Systembeschaffung-und-Entwicklung","R12":"R12_Cloud-KI-und-externe-IT-Dienste", + "R13":"R13_Lieferanten-und-Dienstleistersteuerung","R14":"R14_Compliance-und-Datenschutz"} + +for pol, controls in order_by_pol.items(): + meta=POLICY_META[pol] + body=[META_HEAD.format(title=meta["title"], owner=meta["owner"])] + body.append("\n## 1. Zweck\n\n"+meta["purpose"]+" Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027.\n") + body.append("## 2. Geltungsbereich\n\nDiese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}).\n") + body.append("## 3. Anforderungen und Umsetzung\n\n> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich).\n") + sec=0 + for ctrl,d,is_isa in controls: + sec+=1 + req_block, impl_block, entries=render_reqs(ctrl,d) + mapping["anforderungen"].extend(entries) + isa_label = f"ISA {ctrl}" if is_isa else f"Ergänzung {pol}, nicht ISA" + head=f"### 3.{sec} {d['title']} ({isa_label})\n" + sect = head + "\n**Anforderung**\n\n" + req_block + "\n\n**Umsetzung bei {{ORG_NAME}}**\n\n" + impl_block + "\n" + if d.get("flag"): + sect=f"{{{{#if {d['flag']}}}}}\n{sect}\n{{{{/if}}}}" + body.append(sect) + body.append("## 4. Verbindlichkeit\n\nDiese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch "+meta["owner"]+" überwacht.\n") + roles="\n".join("| %s | %s |"%(r,v) for r,v in meta["roles"]) + body.append("## 5. Rollen und Verantwortlichkeiten\n\n| Rolle | Verantwortung in dieser Richtlinie |\n|-------|-------------------------------------|\n"+roles+"\n") + body.append("## 6. Überprüfung und Aktualisierung\n\nDiese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch "+meta["owner"]+" überprüft und durch {{ROLE_MANAGEMENT}} freigegeben.\n") + body.append("## 7. Nachweise\n\nDie Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}).\n") + rel=", ".join("{{LINK:%s}}"%x for x in meta["related"]) + body.append("## 8. Verwandte Dokumente\n\n- Technische Sicherheits-Baseline: {{LINK:BASELINE}}\n- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}}\n- Nachweisregister: {{LINK:NACHWEISREGISTER}}\n- Weitere: "+rel+"\n\n\n") + open(os.path.join(RDIR,FN[pol]+".md"),"w",encoding="utf-8").write("\n".join(body)) + +# ---- L00 / 1.1.1 Mapping-Eintraege (Leitlinie, kombiniert) ---- +d11=DATA["1.1.1"] +for lvl in ["must","should"]: + for i,text in enumerate(d11[lvl],1): + rid=f"1.1.1-{LETTER[lvl]}{i}" + mapping["anforderungen"].insert(0 if lvl=="must" else len(mapping["anforderungen"]), { + "id":rid,"policy":"L00","control":"1.1.1","level":lvl, + "type":{"must":"MUSS","should":"SOLL"}[lvl],"is_isa":True, + "req_anchor":f"REQ {rid}","impl_anchor":f"REQ {rid}","condition":COND[lvl], + "requirement":text,"link":"{{LINK:L00#1.1.1}}","nachweis_link":"{{LINK:NACHWEISREGISTER}}"}) + +# stabil sortieren nach Control dann Level dann Nummer fuer Lesbarkeit +lvlord={"must":0,"should":1,"high":2,"vhigh":3} +def ctrlkey(c): + base=c.replace("-KI","") + parts=base.split(".") + return tuple(int(p) for p in parts)+ (1 if "-KI" in c else 0,) +mapping["anforderungen"].sort(key=lambda a:(ctrlkey(a["control"]), lvlord[a["level"]], a["id"])) + +json.dump(mapping, open(os.path.join(BASE,"mapping.json"),"w",encoding="utf-8"), ensure_ascii=False, indent=1) + +cnt=collections.Counter(a["level"] for a in mapping["anforderungen"] if a["is_isa"]) +custom=sum(1 for a in mapping["anforderungen"] if not a["is_isa"]) +print("Richtlinien R01-R14 neu generiert.") +print("ISA-Anforderungen im Mapping:", dict(cnt), "Summe", sum(cnt.values())) +print("Kundenspezifische (KI) Zusatz:", custom) diff --git a/seed/isms-vorlagenpaket-v2/_generate_verfahren.py b/seed/isms-vorlagenpaket-v2/_generate_verfahren.py new file mode 100644 index 0000000..c56dd3e --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_generate_verfahren.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +"""Generiert 13 Verfahrensanweisungen (VA-01..VA-13) auditfest: +Zweck, Ausloeser, Eingaben, Ablauf, RACI, Ergebnis/Nachweis, KPI, Verwandte Dokumente. +Erweitert mapping.json um 'verfahren' und annotiert Anforderungen mit erfuellenden Verfahren. +Ergaenzt {{LINK:VA-xx}} in den zugehoerigen Richtlinien.""" +import os, json, re +BASE=os.path.dirname(__file__) +VDIR=os.path.join(BASE,"verfahren"); os.makedirs(VDIR, exist_ok=True) + +# step = (Text, R, A, C, I) +P=[] +def va(**k): P.append(k) + +va(id="VA-01", fn="VA-01_Incident-Response-und-Meldeverfahren", title="Incident-Response- und Meldeverfahren", + owner="{{ROLE_ISB}}", policy="R04", fulfills=["1.6.1-M1","1.6.1-M2","1.6.2-M1","1.6.2-M2","1.6.2-S1","1.6.2-S2"], + purpose="Dieses Verfahren regelt Meldung, Bewertung, Behandlung und Nachbereitung von Informationssicherheitsvorfällen.", + trigger="Meldung eines Sicherheitsereignisses (Mitarbeitende, Technik/Monitoring, Externe) über den definierten Meldeweg.", + inputs=["Meldung/Alarm mit Kurzbeschreibung","Betroffene Systeme/Informationen (Asset-Inventar)","Klassifizierung/Schutzbedarf"], + steps=[ + ("Ereignis melden: Meldung über {{TOOL_TICKET}} bzw. E-Mail an {{ROLE_ISB}} erfassen.","Meldende Person","{{ROLE_ISB}}","-","-"), + ("Triage & Klassifizierung: Relevanz, Schweregrad und Kategorie festlegen.","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","-"), + ("Eindämmung: Sofortmaßnahmen zur Begrenzung des Schadens einleiten.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_MANAGEMENT}}"), + ("Behebung & Wiederherstellung: Ursache beseitigen, Normalbetrieb herstellen.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-"), + ("Meldepflichten prüfen: Kunden/OEM, Behörden, bei personenbezogenen Daten {{ROLE_DPO}} (72-Stunden-Frist).","{{ROLE_ISB}}","{{ROLE_MANAGEMENT}}","{{ROLE_DPO}}","-"), + ("Dokumentation & Lessons Learned: Vorfall abschließen, Verbesserungsmaßnahmen ableiten.","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","{{ROLE_MANAGEMENT}}"), + ], + output="Dokumentierter, abgeschlossener Vorfall im {{TOOL_TICKET}}; abgeleitete Maßnahmen im ISMS-Tool ({{TOOL_NAME}}).", + kpis=["Zeit bis Ersterfassung (Time-to-Detect/Acknowledge)","Zeit bis Behebung (Time-to-Resolve)","Anteil fristgerechter Meldungen"], + related=["R04","VA-02"]) + +va(id="VA-02", fn="VA-02_IT-Notfall-und-Wiederanlaufverfahren", title="IT-Notfall- und Wiederanlaufverfahren (BCM)", + owner="{{ROLE_IT_LEAD}}", policy="R04", fulfills=["1.6.3-M1","1.6.3-S1","5.2.8-M1","5.2.8-S1"], + purpose="Dieses Verfahren regelt die Aufrechterhaltung und Wiederherstellung kritischer IT-Dienste bei Ausfall oder Krise.", + trigger="Ausfall kritischer IT-Dienste, Notfall oder Krisenfall (Eskalation aus VA-01).", + inputs=["Liste kritischer IT-Dienste mit RTO/RPO","Wiederanlaufpläne","Backup-Status (VA-05)"], + steps=[ + ("Notfall feststellen & einstufen: Ausmaß bewerten, ggf. Krisenstab einberufen.","{{ROLE_IT_LEAD}}","{{ROLE_MANAGEMENT}}","{{ROLE_ISB}}","-"), + ("Kommunikation aktivieren: Interne/externe Stakeholder informieren.","{{ROLE_ISB}}","{{ROLE_MANAGEMENT}}","-","Mitarbeitende"), + ("Wiederanlauf priorisieren: Dienste nach RTO/RPO in Reihenfolge bringen.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-"), + ("Wiederherstellung durchführen: Systeme/Daten aus Backup (VA-05) wiederherstellen.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Rückkehr zum Normalbetrieb bestätigen & dokumentieren.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","{{ROLE_MANAGEMENT}}"), + ("Nachbereitung & Test-Update: Plan aktualisieren, {{BACKUP_TEST_FREQ}} üben.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Wiederhergestellte Dienste; dokumentierter Notfall/Test im ISMS-Tool ({{TOOL_NAME}}); aktualisierte Wiederanlaufpläne.", + kpis=["Einhaltung RTO/RPO","Erfolgsquote Wiederherstellungstests","Aktualität der Notfallpläne"], + related=["R04","VA-01","VA-05"]) + +va(id="VA-03", fn="VA-03_Berechtigungsverfahren", title="Berechtigungsverfahren (Joiner/Mover/Leaver und Rezertifizierung)", + owner="{{ROLE_IT_LEAD}}", policy="R08", fulfills=["4.1.1-S1","4.1.3-M1","4.2.1-M1","4.2.1-M2","4.2.1-S1"], + purpose="Dieses Verfahren regelt Beantragung, Genehmigung, Änderung, Entzug und regelmäßige Überprüfung von Zugriffsrechten.", + trigger="Eintritt, Rollenwechsel oder Austritt einer Person; Berechtigungsantrag; fällige Rezertifizierung.", + inputs=["Personalmeldung (HR)","Rollen-/Rechtekatalog (RBAC)","Bestehende Berechtigungen aus {{TOOL_IAM}}"], + steps=[ + ("Antrag erfassen: Zugang/Recht im {{TOOL_TICKET}} beantragen (Joiner/Mover).","Vorgesetzte/Fachbereich","{{ROLE_IT_LEAD}}","-","-"), + ("Fachliche Genehmigung: Erforderlichkeit nach Minimalprinzip prüfen und freigeben.","Fachbereich/Dateneigentümer","Fachbereich/Dateneigentümer","{{ROLE_ISB}}","-"), + ("Umsetzung: Rechte rollenbasiert in {{TOOL_IAM}} setzen.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","Antragsteller"), + ("Leaver/Änderung: Bei Austritt/Wechsel Rechte unverzüglich entziehen/anpassen.","{{ROLE_IT_LEAD}}","{{ROLE_HR_LEAD}}","-","-"), + ("Rezertifizierung ({{RECERT_FREQ}}, BL-IAM-05): Owner bestätigen/entziehen Rechte.","Fachbereich/Dateneigentümer","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","-"), + ("Privilegierte Konten: gesondert prüfen und protokollieren (BL-IAM-06).","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Dokumentierte Anträge/Genehmigungen im {{TOOL_TICKET}}; aktueller Berechtigungsstand in {{TOOL_IAM}}; Rezertifizierungsnachweis.", + kpis=["Anteil fristgerecht entzogener Leaver-Rechte","Rezertifizierungsquote","Zahl verwaister/privilegierter Konten"], + related=["R08","VA-01"]) + +va(id="VA-04", fn="VA-04_Change-und-Patch-Management-Verfahren", title="Change- und Patch-Management-Verfahren", + owner="{{ROLE_IT_LEAD}}", policy="R10", fulfills=["5.2.1-M1","5.2.5-M1"], + purpose="Dieses Verfahren regelt geplante Änderungen an IT-Systemen sowie das risikoorientierte Einspielen von Patches.", + trigger="Änderungsbedarf, verfügbarer Patch oder identifizierte Schwachstelle (VA-06).", + inputs=["Change-/Patch-Antrag","Risikoeinschätzung","Patch-SLA (BL-OPS-01)"], + steps=[ + ("Change beantragen & klassifizieren (Standard/Normal/Notfall) im {{TOOL_TICKET}}.","Antragsteller","{{ROLE_IT_LEAD}}","-","-"), + ("Risiko-/Auswirkungsbewertung inkl. Rollback-Plan.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-"), + ("Genehmigung durch CAB/verantwortliche Rolle.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-"), + ("Test in getrennter Umgebung (BL-OPS, R10).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Umsetzung in Produktion gemäß Patch-SLA (kritisch {{PATCH_SLA_CRIT}}).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","Betroffene"), + ("Verifikation & Dokumentation des Ergebnisses im {{TOOL_TICKET}}.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Dokumentierte, genehmigte und verifizierte Änderung/Patch im {{TOOL_TICKET}}.", + kpis=["Patch-Compliance je Kritikalität","Anteil erfolgreicher Changes (ohne Rollback)","Durchlaufzeit kritischer Patches"], + related=["R10","VA-06"]) + +va(id="VA-05", fn="VA-05_Backup-und-Restore-Verfahren", title="Backup- und Restore-Verfahren", + owner="{{ROLE_IT_LEAD}}", policy="R10", fulfills=["5.2.9-M1","5.2.9-M2","5.2.9-S1"], + purpose="Dieses Verfahren regelt Datensicherung, Aufbewahrung und Wiederherstellung nach dem {{BACKUP_SCHEME}}-Schema.", + trigger="Regulärer Sicherungslauf; Wiederherstellungsbedarf; geplanter Restore-Test.", + inputs=["Sicherungsplan je System","Klassifizierung/RPO","Backup-Ziele ({{TECH_BACKUP}})"], + steps=[ + ("Sicherung durchführen: automatisierte Backups gemäß {{BACKUP_SCHEME}} (BL-OPS-05).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Überwachung: Erfolg/Fehler prüfen, Fehlläufe nachverfolgen ({{TOOL_TICKET}}).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Schutz & Auslagerung: 1 Kopie offline/immutable, Aufbewahrung {{BACKUP_RETENTION}}.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Restore-Anforderung bearbeiten (bei Bedarf/Notfall, VA-02).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","Anforderer","-"), + ("Wiederherstellungstest ({{BACKUP_TEST_FREQ}}, BL-OPS-06) durchführen & dokumentieren.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Protokollierte Sicherungen; dokumentierte Restore-Tests; Nachweis im ISMS-Tool ({{TOOL_NAME}}).", + kpis=["Backup-Erfolgsquote","Erfolgsquote Restore-Tests","Einhaltung RPO"], + related=["R10","VA-02"]) + +va(id="VA-06", fn="VA-06_Schwachstellenmanagement-Verfahren", title="Schwachstellenmanagement-Verfahren", + owner="{{ROLE_IT_LEAD}}", policy="R10", fulfills=["5.2.5-M1","5.2.5-S1","5.2.6-M1"], + purpose="Dieses Verfahren regelt Erkennung, Bewertung, Behandlung und technische Prüfung von Schwachstellen.", + trigger="Regelmäßiger Scan ({{VULN_SCAN_FREQ}}), Sicherheitsmeldung/CVE, Penetrationstest ({{PENTEST_FREQ}}).", + inputs=["Scan-/Testberichte","Asset-Inventar & Kritikalität","Patch-SLA (BL-OPS-01)"], + steps=[ + ("Identifikation: Schwachstellen-Scan {{VULN_SCAN_FREQ}} (BL-OPS-02) und Meldungen auswerten.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Bewertung & Priorisierung nach Kritikalität und Exponierung.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Behandlung anstoßen: Patch/Change (VA-04) oder kompensierende Maßnahme.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-"), + ("Technische Prüfung: Härtung (BL-OPS-07) und Penetrationstests ({{PENTEST_FREQ}}, BL-OPS-08).","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","Externer Dienstleister","-"), + ("Nachverfolgung & Verifikation der Behebung im {{TOOL_TICKET}}.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Nachverfolgte Schwachstellen mit Behandlungsstatus im {{TOOL_TICKET}}; Testberichte.", + kpis=["Mittlere Behebungszeit je Kritikalität","Offene kritische Schwachstellen","Scan-Abdeckung"], + related=["R10","VA-04"]) + +va(id="VA-07", fn="VA-07_Kryptokonzept-und-Schluesselverwaltung", title="Kryptokonzept und Schlüsselverwaltung", + owner="{{ROLE_IT_LEAD}}", policy="R09", fulfills=["5.1.1-M1","5.1.1-S1","5.1.2-M1","5.1.2-S1"], + purpose="Dieses Verfahren regelt den Einsatz kryptografischer Verfahren und die Verwaltung von Schlüsseln über den Lebenszyklus.", + trigger="Neuer Bedarf an Verschlüsselung/Zertifikaten; Schlüsselerneuerung/-sperrung; Änderung des Stands der Technik.", + inputs=["Zulässige Algorithmen (BL-CRY-02)","Schutzbedarf der Daten","Zertifikats-/Schlüsselbestand"], + steps=[ + ("Bedarf & Verfahren festlegen: zulässige Algorithmen {{CRYPTO_ALGO}} (BL-CRY-02) wählen.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Schlüssel/Zertifikate erzeugen und sicher verteilen (BL-CRY-05).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Speicherung & Zugriffsschutz (getrennte Aufbewahrung, {{#if FLAG_CRYPTO_PKI}}PKI, {{/if}}Berechtigungen).","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Übertragungsschutz sicherstellen: mindestens {{TLS_MIN}} (BL-CRY-01).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Erneuerung/Sperrung/Vernichtung dokumentieren.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Dokumentiertes Kryptokonzept; nachvollziehbarer Schlüssel-/Zertifikatslebenszyklus.", + kpis=["Anteil konformer Verfahren/Algorithmen","Ablaufende Zertifikate ohne Erneuerung","Abdeckung Transportverschlüsselung"], + related=["R09","VA-04"]) + +va(id="VA-08", fn="VA-08_Asset-und-Klassifizierungsverfahren", title="Asset- und Klassifizierungsverfahren", + owner="{{ROLE_IT_LEAD}}", policy="R02", fulfills=["1.3.1-M1","1.3.1-M2","1.3.1-S1","1.3.2-M1","1.3.2-M2","1.3.2-S1"], + purpose="Dieses Verfahren regelt Erfassung, Owner-Zuordnung, Klassifizierung und Pflege von Informationswerten und Assets.", + trigger="Neues/geändertes Asset; Beschaffung; regelmäßige Inventurprüfung.", + inputs=["Beschaffungs-/Änderungsmeldung","Klassifizierungsschema","Asset-Inventar ({{TOOL_NAME}})"], + steps=[ + ("Asset erfassen im Inventar ({{TOOL_NAME}}) mit Attributen.","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Owner zuordnen.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","Asset Owner"), + ("Klassifizieren (Vertraulichkeit/Integrität/Verfügbarkeit) durch Owner.","Asset Owner","Asset Owner","{{ROLE_ISB}}","-"), + ("Handhabungsvorgaben je Schutzklasse anwenden (Kennzeichnung/Speicherung/Löschung BL-DEL-01).","Asset Owner","{{ROLE_ISB}}","-","Mitarbeitende"), + ("Pflege & Review ({{REVIEW_CYCLE}}) auf Aktualität.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Aktuelles, klassifiziertes Asset-Inventar im ISMS-Tool ({{TOOL_NAME}}).", + kpis=["Inventar-Abdeckung","Anteil klassifizierter Assets","Assets ohne Owner"], + related=["R02","VA-03"]) + +va(id="VA-09", fn="VA-09_Risikomanagement-Verfahren", title="Risikomanagement-Verfahren", + owner="{{ROLE_ISB}}", policy="R03", fulfills=["1.4.1-M1","1.4.1-M2","1.4.1-M3","1.4.1-S1"], + purpose="Dieses Verfahren regelt Identifikation, Analyse, Bewertung, Behandlung und Überwachung von Informationssicherheitsrisiken.", + trigger="Neues System/Projekt, Vorfall, Änderung, regelmäßiger Review-Zyklus.", + inputs=["Asset-/Prozessliste","Bewertungsskalen & Akzeptanzschwellen","Bestehendes Risikoregister"], + steps=[ + ("Risiken identifizieren (Assets, Bedrohungen, Schwachstellen).","{{ROLE_ISB}}","{{ROLE_ISB}}","Asset/Prozessverantwortliche","-"), + ("Analysieren & bewerten (Eintritt × Schadenshöhe) im ISMS-Tool ({{TOOL_NAME}}).","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","-"), + ("Behandlung festlegen (reduzieren/vermeiden/übertragen/akzeptieren) und Maßnahmen planen.","{{ROLE_ISB}}","{{ROLE_MANAGEMENT}}","Fachbereich","-"), + ("Restrisiko-Akzeptanz dokumentieren.","{{ROLE_MANAGEMENT}}","{{ROLE_MANAGEMENT}}","{{ROLE_ISB}}","-"), + ("Überwachen & aktualisieren ({{REVIEW_CYCLE}} und anlassbezogen).","{{ROLE_ISB}}","{{ROLE_ISB}}","-","-"), + ], + output="Gepflegtes Risikoregister mit Behandlungsplan und Akzeptanzentscheidungen im ISMS-Tool ({{TOOL_NAME}}).", + kpis=["Anteil behandelter Risiken","Überfällige Maßnahmen","Aktualität des Risikoregisters"], + related=["R03","VA-01"]) + +va(id="VA-10", fn="VA-10_Lieferanten-Onboarding-und-Bewertung", title="Lieferanten-Onboarding- und Bewertungsverfahren", + owner="{{ROLE_ISB}}", policy="R13", fulfills=["6.1.1-M1","6.1.1-M2","6.1.1-S1","6.1.2-M1","6.1.2-S1","6.1.3-M1"], + purpose="Dieses Verfahren regelt Auswahl, sicherheitsbezogene Bewertung, vertragliche Bindung und Überwachung von Lieferanten/Dienstleistern.", + trigger="Neuer Lieferant/Dienstleister mit Zugriff auf Informationen; Vertragsverlängerung; periodische Überprüfung.", + inputs=["Leistungs-/Schutzbedarfsbeschreibung","Risikoklassen (BL-SUP-01)","NDA-/Vertragsvorlagen"], + steps=[ + ("Bedarf & Risikoklasse bestimmen (Schutzbedarf, Zugriff).","Einkauf/Fachbereich","{{ROLE_ISB}}","-","-"), + ("Sicherheitsbewertung (Selbstauskunft/Nachweise/TISAX) durchführen.","{{ROLE_ISB}}","{{ROLE_ISB}}","Fachbereich","-"), + ("NDA & vertragliche Sicherheitsanforderungen vereinbaren.","Einkauf","{{ROLE_MANAGEMENT}}","{{ROLE_ISB}}","-"), + ("Verantwortlichkeiten abgrenzen (Betrieb/Sicherheit/Meldung).","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","-"), + ("Ins Lieferantenverzeichnis ({{TOOL_NAME}}) aufnehmen und {{REVIEW_CYCLE}} überprüfen.","{{ROLE_ISB}}","{{ROLE_ISB}}","-","-"), + ], + output="Bewerteter, vertraglich gebundener Lieferant im Lieferantenverzeichnis ({{TOOL_NAME}}); NDA hinterlegt.", + kpis=["Anteil bewerteter Lieferanten","NDA-Abdeckung","Überfällige Lieferantenprüfungen"], + related=["R13","VA-11"]) + +va(id="VA-11", fn="VA-11_Cloud-und-KI-Freigabeverfahren", title="Cloud- und KI-Freigabeverfahren", + owner="{{ROLE_ISB}}", policy="R12", fulfills=["5.3.4-M1","5.3.4-S1","5.3.4-KI-M1","5.3.4-KI-M2","5.3.4-KI-M3","5.3.4-KI-S1"], + purpose="Dieses Verfahren regelt Bewertung und Freigabe von Cloud- und KI-/GenAI-Diensten sowie die zulässige Nutzung.", + trigger="Antrag zur Nutzung eines Cloud- oder KI-Dienstes.", + inputs=["Dienstbeschreibung & Anbieterinfos","Schutzbedarf/Datenklassen","Vertrags-/DPA-Unterlagen"], + steps=[ + ("Antrag erfassen im {{TOOL_TICKET}} (Dienst, Zweck, Datenklassen).","Antragsteller/Fachbereich","{{ROLE_ISB}}","-","-"), + ("Bewertung: Schutzbedarf, Datenlokation/EU, Mandantentrennung, Exit; bei KI Trainings-/Weitergabe-Ausschluss.","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","{{ROLE_DPO}}"), + ("Vertrag/DPA prüfen (bei KI: Opt-out/Enterprise-Vertrag, EU AI Act).","{{ROLE_ISB}}","{{ROLE_MANAGEMENT}}","{{ROLE_DPO}}","-"), + ("Freigabe & Aufnahme in die Freigabeliste ({{TOOL_NAME}}); zulässige Datenklassen festlegen.","{{ROLE_ISB}}","{{ROLE_ISB}}","-","Fachbereich"), + ("Nutzung & Kontrolle: Human-in-the-Loop bei KI, periodische Überprüfung ({{REVIEW_CYCLE}}).","Fachbereich","{{ROLE_ISB}}","-","-"), + ], + output="Freigabeentscheidung und Freigabeliste im ISMS-Tool ({{TOOL_NAME}}); dokumentierte zulässige Datenklassen.", + kpis=["Anteil freigegebener vs. genutzter Dienste","Schatten-IT-Funde","Überfällige Dienst-Reviews"], + related=["R12","VA-10"]) + +va(id="VA-12", fn="VA-12_Awareness-und-Schulungsverfahren", title="Awareness- und Schulungsverfahren", + owner="{{ROLE_ISB}}", policy="R05", fulfills=["2.1.3-M1","2.1.3-S1"], + purpose="Dieses Verfahren regelt Planung, Durchführung und Nachweis von Sensibilisierung und Schulung zur Informationssicherheit.", + trigger="Eintritt neuer Mitarbeitender; jährlicher Schulungszyklus; anlassbezogen nach Vorfällen.", + inputs=["Schulungsplan/Curriculum (BL-HR-01)","Zielgruppen/Rollen","Teilnahmestatus ({{TOOL_NAME}})"], + steps=[ + ("Schulungsbedarf & Zielgruppen planen (rollenspezifisch).","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_HR_LEAD}}","-"), + ("Onboarding-Schulung bei Eintritt durchführen.","{{ROLE_HR_LEAD}}","{{ROLE_ISB}}","-","Mitarbeitende"), + ("Regelmäßige Schulung ({{REVIEW_CYCLE}}, BL-HR-01) durchführen.","{{ROLE_ISB}}","{{ROLE_ISB}}","-","Mitarbeitende"), + ("Wirksamkeit prüfen (Phishing-Simulation) und nachschulen.","{{ROLE_ISB}}","{{ROLE_ISB}}","{{ROLE_IT_LEAD}}","-"), + ("Teilnahme nachweisen im ISMS-Tool ({{TOOL_NAME}}).","{{ROLE_HR_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Dokumentierte Schulungsteilnahme und Wirksamkeitsmessung im ISMS-Tool ({{TOOL_NAME}}).", + kpis=["Schulungsquote","Phishing-Klickrate","Anteil rollenspezifischer Schulungen"], + related=["R05","VA-01"]) + +va(id="VA-13", fn="VA-13_Logging-und-Monitoring-Verfahren", title="Logging- und Monitoring-Verfahren", + owner="{{ROLE_IT_LEAD}}", policy="R10", fulfills=["5.2.4-M1","5.2.4-S1"], + purpose="Dieses Verfahren regelt Erhebung, Schutz, Auswertung und Aufbewahrung sicherheitsrelevanter Protokolldaten.", + trigger="Kontinuierlicher Betrieb; sicherheitsrelevantes Ereignis; Alarm aus {{TECH_SIEM}}.", + inputs=["Log-Quellen/Systeme","Aufbewahrungsvorgaben (BL-OPS-04)","Alarmierungsregeln"], + steps=[ + ("Log-Quellen anbinden und zentral in {{TECH_SIEM}} erfassen (BL-OPS-04).","{{ROLE_IT_LEAD}}","{{ROLE_IT_LEAD}}","-","-"), + ("Manipulationsschutz & Aufbewahrung {{LOG_RETENTION}} sicherstellen.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Auswertung & Alarmierung: Regeln pflegen, Auffälligkeiten prüfen.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Verdachtsfall an Incident-Response (VA-01) übergeben.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ("Regelmäßige Überprüfung der Abdeckung und Regeln.","{{ROLE_IT_LEAD}}","{{ROLE_ISB}}","-","-"), + ], + output="Zentrale, geschützte Protokollierung mit Auswertung; Nachweis im ISMS-Tool ({{TOOL_NAME}}).", + kpis=["Log-Quellen-Abdeckung","Mittlere Zeit bis Alarmreaktion","Anteil auswertbarer Ereignisse"], + related=["R10","VA-01"]) + +# ---------- Rendering ---------- +def render(p): + L=[] + L.append(f"# {p['title']}\n") + L.append("| Dokumenteninformation | Wert |") + L.append("|-----------------------|------|") + L.append(f"| Dokumententyp | Verfahrensanweisung ({p['id']}) |") + L.append("| Geltungsbereich | {{ISMS_SCOPE}} |") + L.append("| Organisation | {{ORG_NAME}} |") + L.append(f"| Prozessverantwortlich | {p['owner']} |") + L.append("| Freigabe durch | {{ROLE_ISB}} |") + L.append("| Version | {{DOC_VERSION}} |") + L.append("| Datum | {{DOC_DATE}} |") + L.append("| Status | {{DOC_STATUS}} |") + L.append(f"\n\n") + L.append("## 1. Zweck\n\n"+p["purpose"]+f" Es operationalisiert die zugehörige Richtlinie ({{{{LINK:{p['policy']}}}}}).\n") + L.append("## 2. Geltungsbereich\n\nGilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}).\n") + L.append("## 3. Auslöser\n\n"+p["trigger"]+"\n") + L.append("## 4. Eingaben\n\n"+"\n".join("- "+i for i in p["inputs"])+"\n") + L.append("## 5. Ablauf\n") + for n,s in enumerate(p["steps"],1): + L.append(f"{n}. {s[0]}") + L.append("\n## 6. RACI\n") + L.append("| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) |") + L.append("|---|---------|------------------|------------------|-----------------|----------------|") + for n,s in enumerate(p["steps"],1): + short=s[0].split(":")[0] if ":" in s[0] else s[0][:40] + L.append(f"| {n} | {short} | {s[1]} | {s[2]} | {s[3]} | {s[4]} |") + L.append("\n## 7. Ergebnis & Nachweis\n\n"+p["output"]+" Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert.\n") + L.append("## 8. Kennzahlen (KPI)\n\n"+"\n".join("- "+k for k in p["kpis"])+"\n") + L.append("## 9. Verwandte Dokumente\n") + rel="\n".join("- "+("Zugehörige Richtlinie: " if x==p['policy'] else "")+f"{{{{LINK:{x}}}}}" for x in p["related"]) + L.append(rel) + L.append("- Technische Sicherheits-Baseline: {{LINK:BASELINE}}") + L.append("- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}}") + L.append("\n\n") + return "\n".join(L) + +for p in P: + open(os.path.join(VDIR,p["fn"]+".md"),"w",encoding="utf-8").write(render(p)) + +# ---------- mapping.json erweitern ---------- +mp=os.path.join(BASE,"mapping.json") +d=json.load(open(mp,encoding="utf-8")) +d["verfahren"]=[{"id":p["id"],"title":p["title"],"file":"verfahren/"+p["fn"]+".md", + "policy":p["policy"],"fulfills":p["fulfills"],"link":"{{LINK:%s}}"%p["id"]} for p in P] +# Annotation je Anforderung +by_req={} +for p in P: + for rid in p["fulfills"]: by_req.setdefault(rid,[]).append(p["id"]) +for a in d["anforderungen"]: + a["verfahren"]=by_req.get(a["id"],[]) +json.dump(d,open(mp,"w",encoding="utf-8"),ensure_ascii=False,indent=1) + +# ---------- {{LINK:VA-xx}} in Richtlinien ergaenzen ---------- +pol2va={} +for p in P: pol2va.setdefault(p["policy"],[]).append(p["id"]) +for fp in [os.path.join(BASE,"richtlinien",f) for f in os.listdir(os.path.join(BASE,"richtlinien"))]: + pid=os.path.basename(fp).split("_")[0] + if pid in pol2va: + txt=open(fp,encoding="utf-8").read() + line="- Zugehörige Verfahren: "+", ".join("{{LINK:%s}}"%v for v in pol2va[pid]) + if "Zugehörige Verfahren" not in txt and "- Technische Sicherheits-Baseline: {{LINK:BASELINE}}" in txt: + txt=txt.replace("- Technische Sicherheits-Baseline: {{LINK:BASELINE}}", + line+"\n- Technische Sicherheits-Baseline: {{LINK:BASELINE}}") + open(fp,"w",encoding="utf-8").write(txt) + +print("Verfahren erstellt:",len(P)) +print("Anforderungen mit Verfahren:",sum(1 for a in d["anforderungen"] if a["verfahren"])) +print("Policies mit Verfahrenslink:",sorted(pol2va)) diff --git a/seed/isms-vorlagenpaket-v2/_isa_de.py b/seed/isms-vorlagenpaket-v2/_isa_de.py new file mode 100644 index 0000000..7626f54 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_isa_de.py @@ -0,0 +1,656 @@ +# -*- coding: utf-8 -*- +# Faithful deutsche 1:1-Uebernahme aller ISA-2027-Anforderungen (Information Security) +# je Control: must / should / high / vhigh (Reihenfolge = ISA-Reihenfolge). +# 'impl' = gebuendelte auditfeste Umsetzung (Normalniveau), 'impl_elev' = Ergaenzung bei hohem/sehr hohem Schutzbedarf. +DATA = {} + +DATA["1.1.1"] = dict(policy="L00", title="Informationssicherheitsrichtlinien", + must=[ + "Die Anforderungen der Informationssicherheit sind bestimmt, dokumentiert und an den Zielen der Organisation ausgerichtet.", + "Eine Leitlinie existiert und ist durch die Leitung der Organisation genehmigt.", + "Die Leitlinie benennt Ziele und die Bedeutung der Informationssicherheit innerhalb der Organisation.", + "Die Leitlinien werden den Beschäftigten in geeigneter Form zur Verfügung gestellt (z. B. Intranet).", + "Beschäftigte und externe Geschäftspartner werden über für sie relevante Änderungen informiert.", + ], should=[ + "Die Informationssicherheitsanforderungen basieren auf der Strategie der Organisation; Gesetze und Verträge werden in der Leitlinie berücksichtigt.", + "Die Leitlinie benennt Konsequenzen bei Nichteinhaltung.", + "Weitere relevante Sicherheitsrichtlinien sind etabliert.", + "Regelmäßige Überprüfung und ggf. Überarbeitung der Richtlinien sind etabliert.", + ], high=[], vhigh=[], + impl="") # L00 ist die Leitlinie selbst; Umsetzung ist der Leitlinientext (kombiniertes Dokument). + +DATA["1.2.1"] = dict(policy="R01", title="Steuerung der Informationssicherheit", + must=[ + "Der Geltungsbereich des ISMS (die durch das ISMS gesteuerte Organisation) ist definiert.", + "Die Anforderungen der Organisation an das ISMS sind bestimmt.", + "Die Organisationsleitung hat das ISMS beauftragt und genehmigt.", + "Das ISMS stellt der Organisationsleitung geeignete Mittel zur Überwachung und Steuerung bereit (z. B. Managementbewertung).", + "Die anwendbaren Controls sind bestimmt (z. B. ISO-27001-Anwendbarkeitserklärung oder ausgefüllter ISA-Katalog).", + "Die Wirksamkeit des ISMS wird regelmäßig durch die Leitung überprüft.", + ], should=[], high=[], vhigh=[], + impl="Der ISMS-Geltungsbereich, die Anforderungen und die anwendbaren Controls (Anwendbarkeitserklärung/ISA-Katalog) sind im ISMS-Tool ({{TOOL_NAME}}) dokumentiert. Die {{ROLE_MANAGEMENT}} hat das ISMS per Managementbeschluss beauftragt und genehmigt, stellt Ressourcen bereit und überprüft die Wirksamkeit mindestens {{REVIEW_CYCLE}} in einer dokumentierten Managementbewertung; die operative Steuerung liegt bei {{ROLE_ISB}}.") + +DATA["1.2.2"] = dict(policy="R01", title="Organisation der Informationssicherheit", + must=[ + "Verantwortlichkeiten für Informationssicherheit sind definiert, dokumentiert und zugewiesen.", + "Die verantwortlichen Beschäftigten sind definiert, qualifiziert und für ihre Aufgabe befähigt.", + "Die erforderlichen Ressourcen stehen zur Verfügung.", + "Die Ansprechpartner sind innerhalb der Organisation und relevanten Geschäftspartnern bekannt.", + ], should=[ + "Es besteht eine Definition und Dokumentation einer angemessenen Informationssicherheitsstruktur innerhalb der Organisation.", + "Sicherheitsrelevante Rollen, die nicht Teil des ISMS, aber für die Informationssicherheit relevant sind, werden berücksichtigt.", + ], high=[ + "Eine angemessene organisatorische Trennung von Verantwortlichkeiten ist etabliert, um Interessenkonflikte zu vermeiden (Funktionstrennung). (C, I, A)", + ], vhigh=[], + impl="Die Verantwortlichkeiten sind in der Rollen-/Verantwortungsmatrix und im ISMS-Tool ({{TOOL_NAME}}) dokumentiert und den Rolleninhabern sowie relevanten Geschäftspartnern bekannt gemacht. Die Rolle {{ROLE_ISB}} ist benannt, qualifiziert, mit Ressourcen und Weisungsrechten ausgestattet und berichtet direkt an die {{ROLE_MANAGEMENT}}.", + impl_elev="Bei hohem Schutzbedarf ist eine organisatorische Funktionstrennung (z. B. Umsetzung vs. Kontrolle) etabliert; unvermeidbare Doppelrollen werden durch kompensierende Kontrollen (Vier-Augen-Prinzip) abgesichert.") + +DATA["1.2.3"] = dict(policy="R01", title="Informationssicherheit in Projekten", + must=[ + "Projekte werden unter Berücksichtigung der Informationssicherheitsanforderungen klassifiziert.", + ], should=[ + "Verfahren und Kriterien für die Klassifizierung von Projekten sind dokumentiert.", + "In einer frühen Projektphase wird eine Risikobewertung nach dem definierten Verfahren durchgeführt und bei Projektänderungen wiederholt.", + "Für identifizierte Informationssicherheitsrisiken werden Maßnahmen abgeleitet und im Projekt berücksichtigt.", + ], high=[ + "Die abgeleiteten Maßnahmen werden während des Projekts regelmäßig überprüft und bei Änderungen der Bewertungskriterien neu bewertet. (C, I, A)", + ], vhigh=[], + impl="Projekte werden zu Beginn anhand eines dokumentierten Kriterienkatalogs hinsichtlich Informationssicherheitsbedarf klassifiziert; die Einstufung wird im {{TOOL_TICKET}} bzw. ISMS-Tool dokumentiert. In einer frühen Phase und bei Änderungen erfolgt eine Risikobewertung; abgeleitete Maßnahmen werden als Aufgaben im {{TOOL_TICKET}} nachgehalten und vor Projektabschluss geprüft; bei erhöhtem Schutzbedarf wird {{ROLE_ISB}} eingebunden.", + impl_elev="Bei hohem Schutzbedarf werden die abgeleiteten Maßnahmen fortlaufend im Projektverlauf überprüft und bei geänderten Bewertungskriterien neu bewertet.") + +DATA["1.3.1"] = dict(policy="R02", title="Identifikation von Informationswerten", + must=[ + "Informationswerte und weitere sicherheitsrelevante Assets der Organisation sind identifiziert und erfasst.", + "Die unterstützenden Assets, die die Informationswerte verarbeiten, sind identifiziert und erfasst.", + ], should=[ + "Ein Katalog der relevanten Informationswerte existiert; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], high=[], vhigh=[], + impl="Informationswerte und unterstützende Assets werden im ISMS-Tool ({{TOOL_NAME}}) im Asset-Inventar mit Attributen (Owner, Standort, Schutzbedarf) erfasst und als Katalog gepflegt; Zu-/Abgänge werden über {{TOOL_TICKET}} ausgelöst.") + +DATA["1.3.2"] = dict(policy="R02", title="Klassifizierung von Informationswerten", + must=[ + "Ein konsistentes Schema zur Klassifizierung von Informationswerten hinsichtlich des Schutzziels Vertraulichkeit ist vorhanden.", + "Die Bewertung der identifizierten Informationswerte erfolgt nach den definierten Kriterien und wird dem Klassifizierungsschema zugeordnet.", + "Vorgaben zur Handhabung unterstützender Assets (z. B. Kennzeichnung, Nutzung, Transport, Speicherung, Rückgabe, Löschung/Vernichtung) abhängig von der Klassifizierung sind vorhanden und umgesetzt.", + ], should=[ + "Die Schutzziele Integrität und Verfügbarkeit werden berücksichtigt.", + ], high=[], vhigh=[], + impl="Es gilt ein konsistentes vierstufiges Klassifizierungsschema (Öffentlich / Intern / Vertraulich / Streng vertraulich) für Vertraulichkeit; die Einstufung erfolgt nach definierten Kriterien durch den Asset Owner im ISMS-Tool und berücksichtigt auch Integrität und Verfügbarkeit. Handhabungsvorgaben je Schutzklasse (Kennzeichnung, Speicherung, Transport, Übertragung BL-CRY-01/04, Löschung BL-DEL-01) sind definiert, umgesetzt und bekannt gemacht.") + +DATA["1.3.3"] = dict(policy="R02", title="Nutzung freigegebener externer IT-Dienste/Hardware", + must=[ + "Externe IT-Dienste werden nicht ohne ausdrückliche Bewertung und Umsetzung der Informationssicherheitsanforderungen genutzt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Die externen IT-Dienste sind mit dem Schutzbedarf der verarbeiteten Informationswerte abgestimmt.", + ], should=[ + "Anforderungen an Beschaffung, Inbetriebnahme und Freigabe im Zusammenhang mit der Nutzung externer IT-Dienste sind bestimmt und erfüllt.", + "Ein Verfahren zur Freigabe unter Berücksichtigung des Schutzbedarfs ist etabliert.", + "Externe IT-Dienste und ihre Freigabe sind dokumentiert.", + "Es wird regelmäßig überprüft, dass nur freigegebene externe IT-Dienste genutzt werden.", + ], high=[], vhigh=[], + impl="Externe IT-Dienste/-Komponenten werden vor Nutzung bewertet, mit dem Schutzbedarf abgestimmt und über ein definiertes Verfahren freigegeben; eine Freigabeliste wird im ISMS-Tool ({{TOOL_NAME}}) geführt und regelmäßig auf ausschließliche Nutzung freigegebener Dienste geprüft.") + +DATA["1.3.4"] = dict(policy="R02", title="Freigabe von Software", + must=[ + "Software wird vor Installation oder Nutzung freigegeben; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Die Softwarefreigabe gilt auch für Spezialsoftware wie Wartungswerkzeuge.", + ], should=[ + "Die zu verwaltenden Softwarearten (Firmware, Betriebssysteme, Anwendungen, Bibliotheken, Gerätetreiber) sind bestimmt.", + "Repositorys der verwalteten Software existieren.", + "Die Software-Repositorys sind gegen unbefugte Manipulation geschützt.", + "Die Freigabe von Software wird regelmäßig überprüft.", + "Softwareversionen und Patch-Stände sind bekannt.", + ], high=[], vhigh=[ + "Zusätzliche Anforderungen an die Softwarenutzung (z. B. Kontroll-/Überwachungsbedarf der Nutzung) sind, sofern vorhanden, bestimmt. (C, I, A)", + ], + impl="Software (inkl. Spezial-/Wartungssoftware) wird vor Einsatz freigegeben; eine Liste zugelassener Software (Whitelist) mit bekannten Versionen/Patch-Ständen wird im ISMS-Tool gepflegt, Beschaffung/Freigabe läuft über {{TOOL_TICKET}}. Verwaltete Softwarearten sind bestimmt, Repositorys gegen Manipulation geschützt und Freigaben werden regelmäßig überprüft.", + impl_elev="Bei sehr hohem Schutzbedarf sind zusätzliche Kontroll-/Überwachungsanforderungen an die Softwarenutzung bestimmt und umgesetzt.") + +DATA["1.4.1"] = dict(policy="R03", title="Risikomanagement", + must=[ + "Risikobewertungen werden regelmäßig und anlassbezogen durchgeführt.", + "Informationssicherheitsrisiken werden angemessen bewertet (z. B. Eintrittswahrscheinlichkeit und mögliches Schadensausmaß).", + "Informationssicherheitsrisiken werden dokumentiert.", + "Jedem Informationssicherheitsrisiko ist ein Verantwortlicher (Risk Owner) zugeordnet, der für Bewertung und Behandlung verantwortlich ist.", + ], should=[ + "Ein Verfahren zur Identifikation, Bewertung und Behandlung von Sicherheitsrisiken ist vorhanden.", + "Kriterien für Bewertung und Behandlung von Sicherheitsrisiken existieren.", + "Maßnahmen zur Risikobehandlung und ihre Verantwortlichen sind festgelegt und dokumentiert; ein Maßnahmenplan bzw. eine Umsetzungsübersicht wird nachverfolgt.", + "Bei Änderungen des Umfelds (z. B. Organisationsstruktur, Standort, Regularien) erfolgt zeitnah eine Neubewertung.", + ], high=[], vhigh=[], + impl="Das dokumentierte Risikomanagement-Verfahren mit Bewertungs- und Akzeptanzkriterien wird im ISMS-Tool ({{TOOL_NAME}}) umgesetzt: Risiken werden regelmäßig ({{REVIEW_CYCLE}}) und anlassbezogen identifiziert, bewertet (Eintritt × Schaden) und dokumentiert; je Risiko sind Risk Owner, Behandlungsoption und Maßnahmen mit Terminen hinterlegt und werden nachverfolgt. Restrisiken akzeptiert die {{ROLE_MANAGEMENT}} dokumentiert.") + +DATA["1.5.1"] = dict(policy="R03", title="Prüfung der Einhaltung im IS-Betrieb", + must=[ + "Die Einhaltung der Richtlinien wird organisationsweit überprüft.", + "Informationssicherheitsrichtlinien und -verfahren werden regelmäßig überprüft.", + "Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt.", + "Die Einhaltung von Informationssicherheitsanforderungen (z. B. technische Vorgaben) wird regelmäßig überprüft.", + "Die Ergebnisse der durchgeführten Überprüfungen werden aufgezeichnet und aufbewahrt.", + ], should=[ + "Ein Plan für Inhalt und Rahmenbedingungen (Zeitplan, Umfang, Controls) der durchzuführenden Überprüfungen liegt vor.", + ], high=[], vhigh=[], + impl="Die Einhaltung von Richtlinien, Verfahren und technischen Anforderungen wird organisationsweit nach einem Auditplan durch interne Audits und Kontrollen regelmäßig überprüft; Ergebnisse werden aufgezeichnet und aufbewahrt, Abweichungen als Maßnahmen im ISMS-Tool nachverfolgt.") + +DATA["1.5.2"] = dict(policy="R03", title="Unabhängige Überprüfung des ISMS", + must=[ + "Informationssicherheitsüberprüfungen werden durch eine unabhängige und kompetente Stelle regelmäßig und nach grundlegenden Änderungen durchgeführt.", + "Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt.", + ], should=[ + "Die Ergebnisse durchgeführter Überprüfungen werden dokumentiert und der Organisationsleitung berichtet.", + ], high=[], vhigh=[], + impl="Das ISMS wird regelmäßig und nach grundlegenden Änderungen durch eine unabhängige, kompetente Stelle (interne Revision oder externe Auditierung, z. B. TISAX) überprüft; Ergebnisse werden dokumentiert, der {{ROLE_MANAGEMENT}} berichtet und Abweichungen als Maßnahmen verfolgt.") + +DATA["1.6.1"] = dict(policy="R04", title="Meldung von Sicherheitsereignissen", + must=[ + "Eine Definition für ein meldepflichtiges Sicherheitsereignis oder eine Beobachtung existiert und ist Beschäftigten und relevanten Stakeholdern bekannt.", + "Angemessene, risikoorientierte Mechanismen zur Meldung von Sicherheitsereignissen sind definiert, umgesetzt und allen relevanten Meldenden bekannt.", + "Angemessene Kanäle zur Kommunikation mit Meldenden existieren.", + ], should=[ + "Eine gemeinsame Anlaufstelle für die Ereignismeldung existiert.", + "Verschiedene Meldekanäle je nach wahrgenommener Schwere (Echtzeit für gravierende Ereignisse/Notfälle sowie asynchrone Mechanismen wie Tickets oder E-Mail) sind verfügbar.", + "Beschäftigte sind verpflichtet und geschult, relevante Ereignisse zu melden.", + "Sicherheitsereignisse können auch durch Externe gemeldet werden; die einschlägigen Aspekte werden berücksichtigt.", + "Der Mechanismus und die Information, wie Vorfälle gemeldet werden, sind für alle relevanten Meldenden zugänglich.", + "Ein Rückmeldeverfahren an die Meldenden ist etabliert.", + ], high=[], vhigh=[ + "Tests und Übungen der Ereignis- und Beobachtungsmeldung werden regelmäßig durchgeführt. (C, I, A)", + ], + impl="Eine bekannte Definition meldepflichtiger Ereignisse und ein niedrigschwelliger Meldeweg (Meldebutton/Formular im {{TOOL_TICKET}} bzw. ISMS-Tool, E-Mail an {{ROLE_ISB}}, für gravierende Fälle Echtzeitkanal) stehen allen Beschäftigten und Externen zur Verfügung; der Meldeweg ist über Onboarding/Awareness (BL-HR-01) bekannt, ein Rückmeldeverfahren ist etabliert.", + impl_elev="Bei sehr hohem Schutzbedarf werden Tests und Übungen der Ereignismeldung regelmäßig durchgeführt.") + +DATA["1.6.2"] = dict(policy="R04", title="Behandlung von Sicherheitsereignissen", + must=[ + "Gemeldete Ereignisse werden ohne unangemessene Verzögerung bearbeitet.", + "Eine angemessene Reaktion auf gemeldete Sicherheitsereignisse ist sichergestellt.", + "Lessons Learned fließen in die kontinuierliche Verbesserung ein.", + ], should=[ + "Gemeldete Ereignisse werden bei der Bearbeitung kategorisiert (z. B. Personal, physisch, Cyber), qualifiziert (z. B. nicht sicherheitsrelevant, Beobachtung, Verbesserungsvorschlag, Schwachstelle, Vorfall) und priorisiert (z. B. gering, mittel, schwer, kritisch).", + "Verantwortlichkeiten für die Behandlung von Ereignissen je Kategorie sind definiert und zugewiesen.", + "Eine Strategie zur Meldung potenziell strafrechtlich relevanter Aspekte an zuständige Behörden, sofern erforderlich, existiert. (C, I, A)", + ], high=[ + "Maximale Reaktionszeiten je Klasse, Kategorie und Schwere sind definiert. (C, I, A)", + "Nicht prioritätsgerecht bearbeitete Ereignisse werden eskaliert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A)", + "Gesetzliche, regulatorische und vertragliche Meldepflichten sowie zugehörige Kontaktinformationen sind bekannt. (C, I, A)", + "Eine Kommunikationsstrategie für sicherheitsrelevante Ereignisse existiert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A)", + "Verfahren zur Reaktion auf Sicherheitsvorfälle bei Lieferanten sind etabliert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A)", + ], vhigh=[ + "Die Behandlung von Ereignissen unterschiedlicher Kategorien und Prioritäten wird regelmäßig getestet; die einschlägigen Aspekte werden berücksichtigt. (A)", + ], + impl="Ereignisse werden ohne Verzögerung nach einem definierten Incident-Verfahren im {{TOOL_TICKET}} kategorisiert, qualifiziert, priorisiert, behandelt und dokumentiert; Verantwortlichkeiten und Eskalationswege sind zugewiesen ({{ROLE_ISB}} koordiniert, {{ROLE_IT_LEAD}} setzt um). Lessons Learned fließen in die Verbesserung ein; eine Strategie zur Behörden-/Strafverfolgungsmeldung besteht.", + impl_elev="Bei hohem Schutzbedarf sind maximale Reaktionszeiten je Schwere definiert, Eskalationen für nicht prioritätsgerecht bearbeitete Ereignisse geregelt, Meldepflichten und Kontakte bekannt, eine Kommunikationsstrategie sowie ein Verfahren für Lieferantenvorfälle etabliert. Bei sehr hohem Schutzbedarf wird die Ereignisbehandlung regelmäßig getestet.") + +DATA["1.6.3"] = dict(policy="R04", title="Krisenmanagement", + must=[ + "Ein angemessener Plan zur Reaktion auf und Bewältigung von Krisensituationen existiert und die erforderlichen Ressourcen sind verfügbar.", + "Verantwortlichkeiten und Befugnisse für das Krisenmanagement sind definiert, dokumentiert und zugewiesen.", + "Die verantwortlichen Beschäftigten sind definiert und für ihre Aufgabe qualifiziert.", + ], should=[ + "Methoden zur Erkennung von Krisensituationen sind etabliert; allgemeine Anzeichen und spezifische vorhersehbare Krisen sind identifiziert.", + "Ein Verfahren zur Auslösung und/oder Eskalation des Krisenmanagements ist vorhanden.", + "Strategische Ziele und ihre Priorität in Krisensituationen sind definiert und relevantem Personal bekannt.", + "Ein Krisenstab ist definiert und genehmigt.", + "Krisenrichtlinien und -verfahren sind definiert und genehmigt.", + "Die Krisenplanung wird regelmäßig überprüft und aktualisiert.", + ], high=[ + "Relevante unterschiedliche potenzielle Krisenszenarien sind identifiziert.", + "Notwendige Ressourcen und Informationen zur Krisenbewältigung (z. B. Kommunikationsinfrastruktur, Verfügbarkeit von Kontakt- und Risikoinformationen) sind identifiziert; angemessene Maßnahmen zur Sicherstellung der Verfügbarkeit bzw. Ausfallplanung sind vorhanden. (A)", + "Eine Kommunikationsstrategie für Krisensituationen existiert. (A)", + "Effizienz, Durchführbarkeit und Angemessenheit der Krisenplanung werden regelmäßig bewertet. (A)", + "Stichprobenbasierte Tests der Krisenplanung werden durchgeführt (z. B. Simulation, Tabletop-Übungen mit Schlüsselpersonal). (A)", + ], vhigh=[ + "Krisenübungen und Simulationen unter Einbindung aller relevanten Personen, einschließlich Entscheidungsträger, werden regelmäßig durchgeführt. (A)", + ], + impl="Ein Krisenmanagement mit Plan, definiertem und genehmigtem Krisenstab, Rollen, Auslöse-/Eskalations-, Kommunikations- und Entscheidungswegen sowie strategischen Zielen ist etabliert; erforderliche Ressourcen sind verfügbar, Verantwortliche qualifiziert. Erkennungsmethoden bestehen, die Krisenplanung wird regelmäßig überprüft und aktualisiert; der Krisenstab wird durch die {{ROLE_MANAGEMENT}} einberufen.", + impl_elev="Bei hohem Schutzbedarf sind relevante Krisenszenarien identifiziert, notwendige Ressourcen/Informationen und eine Kommunikationsstrategie sichergestellt, die Planung wird regelmäßig bewertet und stichprobenartig getestet (Tabletop). Bei sehr hohem Schutzbedarf werden regelmäßig Krisenübungen mit allen relevanten Personen inkl. Entscheidungsträgern durchgeführt.") + +DATA["2.1.1"] = dict(policy="R05", title="Qualifikation für sensible Tätigkeiten", + must=[ + "Sensible Arbeitsbereiche und Tätigkeiten sind bestimmt.", + "Die Anforderungen an Beschäftigte hinsichtlich ihrer Stellenprofile sind bestimmt und erfüllt.", + "Die Identität potenzieller Beschäftigter wird verifiziert (z. B. Prüfung von Ausweisdokumenten).", + ], should=[ + "Die persönliche Eignung potenzieller Beschäftigter wird mit einfachen Methoden überprüft (z. B. Vorstellungsgespräch).", + "Eine erweiterte Eignungsprüfung abhängig vom Arbeitsbereich und der Tätigkeit wird durchgeführt (z. B. Assessment-Center, Prüfung von Referenzen, Zeugnissen und Führungszeugnissen).", + ], high=[], vhigh=[], + impl="Sensible Tätigkeiten sind bestimmt; Anforderungen an Positionen sind in Stellenbeschreibungen hinterlegt und werden erfüllt. Die Identität wird bei Einstellung verifiziert; die persönliche Eignung wird im rechtlich zulässigen Rahmen geprüft (Gespräch, bei sensiblen Rollen erweiterte Prüfungen wie Referenzen/Führungszeugnis).") + +DATA["2.1.2"] = dict(policy="R05", title="Vertragliche Verpflichtung des Personals", + must=[ + "Eine Vertraulichkeitsverpflichtung ist in Kraft.", + "Eine Verpflichtung zur Einhaltung der Informationssicherheitsrichtlinien ist in Kraft.", + ], should=[ + "Eine über den Arbeitsvertrag hinausgehende Vertraulichkeitsverpflichtung ist in Kraft.", + "Informationssicherheitsaspekte werden in den Arbeitsverträgen der Beschäftigten berücksichtigt.", + "Ein Verfahren zum Umgang mit Verstößen gegen diese Verpflichtungen ist beschrieben.", + ], high=[], vhigh=[], + impl="Alle Beschäftigten werden bei Eintritt vertraglich zur Vertraulichkeit und zur Einhaltung der Informationssicherheitsrichtlinien verpflichtet ({{ROLE_HR_LEAD}}); Informationssicherheitsaspekte sind Bestandteil der Arbeitsverträge, die Vertraulichkeit gilt nachvertraglich fort. Ein Verfahren zum Umgang mit Verstößen ist beschrieben; der Nachweis wird in der Personalakte geführt.") + +DATA["2.1.3"] = dict(policy="R05", title="Sensibilisierung und Schulung", + must=[ + "Beschäftigte werden geschult und sensibilisiert.", + ], should=[ + "Ein Konzept für Sensibilisierung und Schulung der Beschäftigten ist erstellt.", + "Zielgruppen für Schulungs- und Sensibilisierungsmaßnahmen (z. B. Führungskräfte, Administratoren, Beschäftigte mit Zugang zu Kundennetzen, Fertigungspersonal) sind identifiziert und im Konzept berücksichtigt.", + "Das Konzept ist durch die verantwortliche Leitung genehmigt.", + "Schulungs- und Sensibilisierungsmaßnahmen werden regelmäßig und anlassbezogen durchgeführt.", + "Die Teilnahme an Schulungs- und Sensibilisierungsmaßnahmen wird dokumentiert.", + "Ansprechpartner für Informationssicherheit sind den Beschäftigten bekannt.", + ], high=[], vhigh=[], + impl="Ein von der Leitung genehmigtes, rollenspezifisches Schulungs-/Awareness-Konzept (BL-HR-01) ist etabliert; Beschäftigte werden bei Eintritt und danach mindestens {{REVIEW_CYCLE}} sowie anlassbezogen geschult. Zielgruppen sind identifiziert, Teilnahmenachweise werden im {{TOOL_NAME}} geführt, Ansprechpartner für Informationssicherheit sind bekannt; die Wirksamkeit wird (z. B. Phishing-Simulation) geprüft.") + +DATA["2.1.4"] = dict(policy="R06", title="Mobiles Arbeiten", + must=[ + "Die Anforderungen an mobiles Arbeiten sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], should=[ + "Die einschlägigen Aspekte des mobilen Arbeitens werden berücksichtigt.", + "Sensibilisierung der Beschäftigten.", + ], high=[ + "Schutzmaßnahmen gegen Abhören und Einsehen sind umgesetzt. (C)", + ], vhigh=[], + flag="FLAG_MOBILE_WORK", + impl="Mobiles Arbeiten ist in einer Regelung festgelegt und die Anforderungen sind erfüllt; der Zugriff erfolgt ausschließlich über {{TECH_VPN}} mit MFA (BL-IAM-02) und freigegebene, verschlüsselte Geräte (BL-CRY-03). Die Beschäftigten sind sensibilisiert (BL-HR-01).", + impl_elev="Bei hohem Schutzbedarf sind Schutzmaßnahmen gegen Abhören und Einsehen umgesetzt (z. B. Sichtschutz, ruhige Umgebung, Clean-Screen).") + +DATA["3.1.1"] = dict(policy="R07", title="Sicherheitszonen und Zutritt", + must=[ + "Ein Sicherheitszonenkonzept einschließlich zugehöriger Schutzmaßnahmen auf Basis der Anforderungen an die Handhabung von Informationswerten ist vorhanden.", + "Die definierten Schutzmaßnahmen sind umgesetzt.", + "Der Verhaltenskodex für Sicherheitszonen ist allen beteiligten Personen bekannt.", + ], should=[ + "Verfahren für die Vergabe und den Entzug von Zutrittsrechten sind etabliert.", + "Richtlinien für das Besuchermanagement (einschließlich Registrierung und Begleitung von Besuchern) sind definiert.", + "Richtlinien für das Mitführen und Nutzen mobiler IT-Geräte und Datenträger (z. B. Registrierung, Kennzeichnungspflichten) sind definiert und umgesetzt.", + "Netzwerk-/Infrastrukturkomponenten (eigene oder Kundennetze) sind gegen unbefugten Zugriff geschützt.", + "Externe Liegenschaften zur Speicherung/Verarbeitung von Informationswerten sind im Zonenkonzept berücksichtigt (z. B. Lagerräume, Werkstätten, Teststrecken, Rechenzentren).", + ], high=[ + "Schutzmaßnahmen gegen einfaches Abhören und Einsehen sind umgesetzt. (C)", + ], vhigh=[], + impl="Ein Sicherheitszonenkonzept (BL-PHY-01) mit umgesetzten Schutzmaßnahmen und bekanntem Verhaltenskodex ist vorhanden; Zutrittsrechte werden über {{TOOL_TICKET}} bedarfsorientiert vergeben, dokumentiert und bei Wegfall entzogen (BL-PHY-02). Besuchermanagement, Regeln für mobile Geräte, Schutz von Netz-/Infrastrukturkomponenten und externe Liegenschaften sind berücksichtigt.", + impl_elev="Bei hohem Schutzbedarf sind zusätzliche Schutzmaßnahmen gegen einfaches Abhören und Einsehen umgesetzt.") + +DATA["3.1.3"] = dict(policy="R07", title="Umgang mit unterstützenden Betriebsmitteln", + must=[], should=[], high=[], vhigh=[], + impl="Der Umgang mit unterstützenden Betriebsmitteln (z. B. Verkabelung, Strom-/Klimaversorgung, Serverräume) ist geregelt; sie sind zutrittsgeschützt, gegen Ausfall abgesichert, werden gewartet und überwacht, für kritische Bereiche bestehen Redundanzen (z. B. USV).") + +DATA["3.1.4"] = dict(policy="R06", title="Mobile IT-Geräte und Datenträger", + must=[ + "Die Anforderungen an mobile IT-Geräte und mobile Datenträger sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], should=[ + "Registrierung der IT-Geräte.", + ], high=[ + "Generelle Verschlüsselung mobiler Datenträger bzw. der darauf gespeicherten Informationswerte. Wo technisch nicht machbar, werden Informationen durch gleichwertige Maßnahmen geschützt. (C, I)", + ], vhigh=[], + flag="FLAG_MOBILE_DEVICES", + impl="Die Anforderungen an mobile Geräte und Datenträger sind bestimmt und erfüllt: Geräte sind über {{TECH_MDM}} registriert und zentral verwaltet, nur freigegebene Geräte werden genutzt; Verlustmeldung erfolgt über den Meldeweg (R04) und {{TOOL_TICKET}}, Sperre/Löschung bei Verlust über {{TECH_MDM}} (BL-EP-02).", + impl_elev="Bei hohem Schutzbedarf sind mobile Datenträger bzw. die darauf gespeicherten Informationen generell verschlüsselt (BL-CRY-03); wo nicht machbar, greifen gleichwertige Schutzmaßnahmen.") + +DATA["4.1.1"] = dict(policy="R08", title="Umgang mit Identifikationsmitteln", + must=[ + "Die Anforderungen an den Umgang mit Identifikationsmitteln über den gesamten Lebenszyklus sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], should=[ + "Identifikationsmittel können nur unter kontrollierten Bedingungen erstellt werden.", + ], high=[ + "Eine Strategie zur Sperrung oder Ungültigmachung von Identifikationsmitteln im Verlustfall ist vorbereitet und soweit möglich umgesetzt. (C, I, A)", + ], vhigh=[], + impl="Identifikationsmittel (Benutzerkennungen, Token, Zertifikate) werden über den Lebenszyklus eindeutig personenbezogen und unter kontrollierten Bedingungen über {{TOOL_IAM}} vergeben; Ausgabe, Rücknahme und Sperrung werden im {{TOOL_TICKET}} beantragt, genehmigt und dokumentiert (BL-IAM-07).", + impl_elev="Bei hohem Schutzbedarf besteht eine umgesetzte Strategie zur Sperrung/Ungültigmachung von Identifikationsmitteln im Verlustfall.") + +DATA["4.1.2"] = dict(policy="R08", title="Sichere Anmeldung", + must=[ + "Die Verfahren zur Benutzerauthentifizierung sind auf Basis einer Risikobewertung ausgewählt; mögliche Angriffsszenarien (z. B. direkte Erreichbarkeit über das Internet) wurden berücksichtigt.", + "Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt.", + ], should=[ + "Die Authentifizierungsverfahren sind auf Basis der geschäftlichen und sicherheitsrelevanten Anforderungen definiert und umgesetzt.", + "Benutzer werden mindestens durch starke Passwörter nach bewährten und anerkannten Praktiken authentifiziert.", + "Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt (z. B. Privileged Access Management, Zwei-Faktor-Authentifizierung).", + ], high=[ + "Abhängig von der Risikobewertung sind Authentifizierung und Zugangskontrolle durch ergänzende Maßnahmen verstärkt (z. B. kontinuierliche Zugriffsüberwachung, starke Authentifizierung, automatische Abmeldung, Sperre bei Inaktivität, Brute-Force-Prävention). (C, I, A)", + ], vhigh=[ + "Vor dem Zugriff auf Daten mit sehr hohem Schutzbedarf werden Benutzer mittels starker Authentifizierung (z. B. Zwei-Faktor) nach dem Stand der Technik authentifiziert. (C, I)", + ], + impl="Die Authentifizierungsverfahren sind risikobasiert ausgewählt und entsprechen dem Stand der Technik; Passwortvorgaben nach BL-IAM-01 (mind. {{PW_MIN_LENGTH}} Zeichen, {{PW_COMPLEXITY}}, {{PW_ROTATION}}) werden zentral über {{TOOL_IAM}} erzwungen. Für Fernzugriffe, administrative Zugänge und Cloud-Dienste wird MFA (BL-IAM-02) über {{TECH_MFA}} durchgesetzt; privilegierte Konten nutzen höherwertige Verfahren (PAM).", + impl_elev="Bei hohem Schutzbedarf sind Authentifizierung/Zugangskontrolle durch ergänzende Maßnahmen verstärkt (Zugriffsüberwachung, Auto-Logout BL-IAM-03, Sperre BL-IAM-04, Brute-Force-Schutz). Bei sehr hohem Schutzbedarf erfolgt der Zugriff nur nach starker Authentifizierung (Zwei-Faktor).") + +DATA["4.1.3"] = dict(policy="R08", title="Benutzerkonten und Anmeldeinformationen", + must=[ + "Das Erstellen, Ändern und Löschen von Benutzerkonten wird durchgeführt.", + "Eindeutige und personalisierte Benutzerkonten werden verwendet.", + "Die Nutzung von Sammelkonten ist geregelt (z. B. beschränkt auf Fälle, in denen Nachvollziehbarkeit verzichtbar ist).", + "Benutzerkonten werden unmittelbar nach dem Ausscheiden des Nutzers deaktiviert (z. B. bei Vertragsende).", + "Benutzerkonten werden regelmäßig überprüft.", + "Die Anmeldeinformationen werden dem Nutzer auf sichere Weise bereitgestellt.", + "Eine Richtlinie zum Umgang mit Anmeldeinformationen ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], should=[ + "Ein Basiskonto mit minimalen Zugriffsrechten und Funktionalitäten existiert und wird genutzt.", + "Vom Hersteller vorkonfigurierte Standardkonten und -passwörter sind deaktiviert (z. B. Sperren oder Passwortänderung).", + "Benutzerkonten werden durch die verantwortliche Stelle erstellt oder autorisiert.", + "Das Erstellen von Benutzerkonten unterliegt einem Genehmigungsprozess (Vier-Augen-Prinzip).", + "Benutzerkonten von Dienstleistern werden nach Abschluss ihrer Aufgabe deaktiviert.", + "Fristen für das Deaktivieren und Löschen von Benutzerkonten sind definiert.", + "Die Verwendung von Standardpasswörtern wird technisch verhindert.", + "Bei starker Authentifizierung ist die Nutzung des Mediums (z. B. Besitzfaktor) sicher.", + "Benutzerkonten werden regelmäßig überprüft; dies umfasst auch Konten in IT-Systemen von Kunden.", + "Interaktive Anmeldung für Dienstkonten (technische Konten) wird technisch verhindert.", + ], high=[], vhigh=[], + impl="Benutzerkonten werden über einen definierten Lebenszyklus (Joiner/Mover/Leaver) eindeutig personalisiert in {{TOOL_IAM}} verwaltet; Auslöser sind {{TOOL_TICKET}}-Aufträge aus HR-/Vorgesetztenmeldungen. Konten Ausgeschiedener werden unverzüglich deaktiviert, Konten regelmäßig überprüft (auch in Kundensystemen), Sammelkonten sind geregelt. Anmeldeinformationen werden sicher bereitgestellt; Standardkonten/-passwörter sind deaktiviert, Basiskonten mit Minimalrechten genutzt, Erstellung erfolgt im Vier-Augen-Prinzip, interaktive Anmeldung technischer Konten ist unterbunden.") + +DATA["4.2.1"] = dict(policy="R08", title="Zugriffsrechte", + must=[ + "Die Anforderungen an die Verwaltung von Zugriffsrechten (Autorisierung) sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Die für normale und privilegierte Benutzerkonten sowie technische Konten vergebenen Zugriffsrechte werden regelmäßig überprüft, auch in IT-Systemen von Kunden.", + ], should=[ + "Strategien zur Autorisierung von Zugriffen auf Informationen sind vorbereitet.", + "Autorisierungsrollen werden verwendet.", + "Rechte werden nach dem Need-to-use-Prinzip und gemäß Rolle und/oder Verantwortungsbereich vergeben.", + "Normale Benutzerkonten erhalten keine privilegierten Zugriffsrechte.", + "Die Zugriffsrechte des Nutzers werden nach Änderung seiner Verantwortlichkeiten aktualisiert.", + ], high=[ + "Die Zugriffsrechte werden durch den verantwortlichen internen Information Officer genehmigt. (C, I, A)", + ], vhigh=[ + "Informationen werden auf Inhaltsebene (z. B. Dateiebene) verschlüsselt gespeichert, um unbefugten Zugriff (auch privilegierter Nutzer) zu verhindern. Wo Verschlüsselung nicht machbar ist, greifen gleichwertige Maßnahmen. (C)", + "Bestehende Zugriffsrechte werden in kürzeren Abständen (z. B. quartalsweise) überprüft. (C)", + ], + impl="Zugriffsrechte werden nach dem Minimalprinzip (need-to-know/least privilege) rollenbasiert (RBAC) über {{TOOL_IAM}} vergeben; Antrag, fachliche Prüfung und Genehmigung erfolgen im {{TOOL_TICKET}}. Rechte werden bei Änderung/Wegfall aktualisiert bzw. entzogen und mindestens {{RECERT_FREQ}} rezertifiziert (BL-IAM-05), auch in Kundensystemen; Standardkonten erhalten keine privilegierten Rechte.", + impl_elev="Bei hohem Schutzbedarf werden Zugriffsrechte durch den verantwortlichen internen Information Officer genehmigt. Bei sehr hohem Schutzbedarf werden Informationen inhaltsverschlüsselt gespeichert (Schutz auch vor privilegierten Nutzern) und Zugriffsrechte in kürzeren Abständen (z. B. quartalsweise) überprüft.") + +DATA["5.1.1"] = dict(policy="R09", title="Einsatz kryptografischer Verfahren", + must=[ + "Alle eingesetzten kryptografischen Verfahren (z. B. Verschlüsselung, Signatur, Hash-Algorithmen, Protokolle) bieten die im jeweiligen Anwendungsfeld erforderliche Sicherheit nach anerkanntem Industriestandard, soweit rechtlich möglich.", + ], should=[ + "Ein Konzept für den Einsatz von Kryptografie ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], high=[ + "Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) sind bestimmt und erfüllt. (C, I)", + ], vhigh=[], + impl="Zulässige Verfahren und Schlüssellängen nach BL-CRY-02 ({{CRYPTO_ALGO}}) entsprechen dem anerkannten Industriestandard und sind vorgegeben; veraltete Verfahren sind untersagt. Ein Kryptokonzept ist dokumentiert (siehe {{LINK:VA-07}}), Schlüssel werden über ihren Lebenszyklus sicher verwaltet (BL-CRY-05).", + impl_elev="Bei hohem Schutzbedarf sind Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) bestimmt und erfüllt.") + +DATA["5.1.2"] = dict(policy="R09", title="Schutz bei der Informationsübertragung", + must=[ + "Die zur Informationsübertragung genutzten Netzdienste sind identifiziert und dokumentiert.", + "Richtlinien und Verfahren entsprechend den Klassifizierungsanforderungen für die Nutzung von Netzdiensten sind definiert und umgesetzt.", + "Maßnahmen zum Schutz übertragener Inhalte gegen unbefugten Zugriff sind umgesetzt.", + ], should=[ + "Maßnahmen zur Sicherstellung korrekter Adressierung und korrekter Informationsübertragung sind umgesetzt.", + "Elektronischer Datenaustausch erfolgt mittels Inhalts- oder Transportverschlüsselung entsprechend der jeweiligen Klassifizierung.", + "Fernzugriffsverbindungen zum Netzwerk der Organisation verfügen über angemessene Sicherheitsmerkmale; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], high=[ + "Informationen werden verschlüsselt übertragen (mindestens Transportverschlüsselung) oder durch gleichwertig wirksame Maßnahmen geschützt. (C)", + ], vhigh=[ + "Informationen werden inhaltsverschlüsselt übertragen. (C)", + ], + impl="Genutzte Netzdienste sind identifiziert und dokumentiert; Richtlinien/Verfahren entsprechend der Klassifizierung sind umgesetzt. Informationen werden schutzbedarfsgerecht bei der Übertragung geschützt (mindestens {{TLS_MIN}}, BL-CRY-01), korrekte Adressierung sichergestellt und Fernzugriffe abgesichert; Regeln für E-Mail-/Dateiverschlüsselung sind definiert (BL-CRY-04).", + impl_elev="Bei hohem Schutzbedarf werden Informationen mindestens transportverschlüsselt oder gleichwertig geschützt übertragen; bei sehr hohem Schutzbedarf erfolgt eine Inhaltsverschlüsselung.") + +DATA["5.2.1"] = dict(policy="R10", title="Änderungsmanagement (Change)", + must=[ + "Informationssicherheitsanforderungen für Änderungen an Organisation, Geschäftsprozessen und IT-Systemen sind bestimmt und erfüllt.", + ], should=[ + "Ein formales Genehmigungsverfahren ist etabliert.", + "Die möglichen Auswirkungen von Änderungen auf die Informationssicherheit werden bewertet.", + "Änderungen mit Auswirkung auf die Informationssicherheit werden geplant und getestet.", + "Verfahren zum Rückfall (Fallback) in Fehlerfällen werden berücksichtigt.", + ], high=[ + "Die Einhaltung der Informationssicherheitsanforderungen wird während und nach den Änderungen überprüft. (C, I, A)", + ], vhigh=[], + impl="Änderungen durchlaufen ein formales Change-Verfahren mit Antrag, Auswirkungs-/Risikobewertung, Planung, Test, Genehmigung, Rollback-Plan und Dokumentation im {{TOOL_TICKET}} (BL-OPS-09); Informationssicherheitsanforderungen sind bestimmt und erfüllt.", + impl_elev="Bei hohem Schutzbedarf wird die Einhaltung der Informationssicherheitsanforderungen während und nach der Änderung verifiziert.") + +DATA["5.2.2"] = dict(policy="R10", title="Trennung von Entwicklungs-, Test- und Produktivsystemen", + must=[ + "Die IT-Systeme wurden einer Risikobewertung unterzogen, um die Notwendigkeit ihrer Trennung in Entwicklungs-, Test- und Produktivsysteme zu bestimmen.", + "Eine Segmentierung ist auf Basis der Ergebnisse der Risikoanalyse umgesetzt.", + ], should=[ + "Die Anforderungen an Entwicklungs- und Testumgebungen sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], high=[], vhigh=[], + impl="Auf Basis einer Risikobewertung sind Entwicklung, Test und Produktion getrennt betrieben und segmentiert; Anforderungen an Entwicklungs-/Testumgebungen sind bestimmt und erfüllt, Produktivdaten werden dort nur anonymisiert/pseudonymisiert genutzt.") + +DATA["5.2.3"] = dict(policy="R10", title="Schutz vor Schadsoftware", + must=[ + "Anforderungen zum Schutz vor Schadsoftware sind bestimmt.", + "Technische und organisatorische Maßnahmen zum Schutz vor Schadsoftware sind definiert und umgesetzt.", + ], should=[ + "Unnötige Netzwerkdienste sind deaktiviert.", + "Der Zugriff auf Netzwerkdienste ist durch geeignete Schutzmaßnahmen auf das Notwendige beschränkt.", + "Schutzsoftware gegen Schadsoftware ist installiert und wird regelmäßig automatisch aktualisiert (z. B. Virenscanner).", + "Empfangene Dateien und Software werden vor der Ausführung automatisch auf Schadsoftware geprüft (On-Access-Scan).", + "Der gesamte Datenbestand aller Systeme wird regelmäßig auf Schadsoftware geprüft.", + "Über zentrale Gateways übertragene Daten (z. B. E-Mail, Internet, Fremdnetze) werden automatisch durch Schutzsoftware geprüft.", + "Maßnahmen, die verhindern, dass Schutzsoftware durch Nutzer deaktiviert oder verändert wird, sind definiert und umgesetzt.", + "Für IT-Systeme ohne Schutzsoftware sind alternative Maßnahmen umgesetzt (z. B. besondere Resilienz, wenige Dienste, keine aktiven Nutzer, Netzisolation).", + ], high=[], vhigh=[], + impl="Malware-Schutz ist über {{TECH_MALWARE}} auf allen Endpunkten und Servern umgesetzt (BL-OPS-03); Signaturen/Engines aktualisieren sich {{MALWARE_UPDATE}}, On-Access- und regelmäßige Vollscans sowie Gateway-Prüfungen (E-Mail/Internet) sind aktiv. Unnötige Netzwerkdienste sind deaktiviert, der Zugriff ist beschränkt, das Deaktivieren der Schutzsoftware ist unterbunden; für Systeme ohne Schutzsoftware greifen alternative Maßnahmen (Isolation).") + +DATA["5.2.4"] = dict(policy="R10", title="Protokollierung und Auswertung", + must=[ + "Informationssicherheitsanforderungen an den Umgang mit Ereignisprotokollen sind bestimmt und erfüllt.", + "Sicherheitsrelevante Anforderungen an die Protokollierung von Aktivitäten von Administratoren und Nutzern sind bestimmt und erfüllt.", + "Die eingesetzten IT-Systeme werden hinsichtlich der Notwendigkeit der Protokollierung bewertet.", + "Bei Nutzung externer IT-Dienste werden Informationen zu den Überwachungsmöglichkeiten eingeholt und in der Bewertung berücksichtigt.", + "Ereignisprotokolle werden regelmäßig auf Richtlinienverstöße und auffällige Probleme geprüft, unter Einhaltung der zulässigen rechtlichen und organisatorischen Vorgaben.", + ], should=[ + "Ein Verfahren zur Eskalation relevanter Ereignisse an die verantwortliche Stelle ist definiert und etabliert.", + "Ereignisprotokolle (Inhalt und Metadaten) sind gegen Veränderung geschützt (z. B. durch eine dedizierte Umgebung).", + "Eine angemessene Überwachung und Aufzeichnung aller informationssicherheitsrelevanten Aktionen im Netzwerk ist etabliert.", + ], high=[ + "Sicherheitsrelevante Anforderungen an den Umgang mit Ereignisprotokollen, z. B. vertragliche Anforderungen, sind bestimmt und umgesetzt. (C, I, A)", + "Ereignisse zu Auf- und Abbau von Fernzugriffssitzungen (z. B. Fernwartung) werden protokolliert. (C, I, A)", + ], vhigh=[ + "Protokollierung jedes Zugriffs auf Daten mit sehr hohem Schutzbedarf, soweit technisch machbar und rechtlich/organisatorisch zulässig. (C, I)", + ], + impl="Sicherheitsrelevante Ereignisse (inkl. Administrator-/Nutzeraktivitäten) werden nach bestimmten und bewerteten Anforderungen zentral über {{TECH_SIEM}} protokolliert und regelmäßig auf Verstöße ausgewertet (BL-OPS-04); bei externen Diensten werden Überwachungsmöglichkeiten berücksichtigt. Protokolle sind manipulationsgeschützt, Aufbewahrung {{LOG_RETENTION}}, ein Eskalationsverfahren ist etabliert (siehe {{LINK:VA-13}}).", + impl_elev="Bei hohem Schutzbedarf sind zusätzliche (z. B. vertragliche) Protokollanforderungen umgesetzt und Fernzugriffssitzungen werden protokolliert. Bei sehr hohem Schutzbedarf wird jeder Zugriff auf entsprechende Daten protokolliert, soweit technisch/rechtlich zulässig.") + +DATA["5.2.5"] = dict(policy="R10", title="Umgang mit Schwachstellen", + must=[ + "Informationen über technische Schwachstellen der eingesetzten IT-Systeme werden erhoben (z. B. Herstellerinfos, System-Audits, CVE-Datenbank).", + "Potenziell betroffene IT-Systeme und Software werden identifiziert und das durch die Schwachstelle verursachte Risiko wird bewertet.", + "Risiken aus Schwachstellen werden behandelt.", + ], should=[ + "Ein angemessenes Patch-Management ist definiert und umgesetzt (z. B. Patch-Test und -Installation).", + "Risikominimierende Maßnahmen werden bei Bedarf umgesetzt.", + "Die erfolgreiche Installation von Patches wird in geeigneter Weise verifiziert.", + ], high=[], vhigh=[], + impl="Schwachstelleninformationen werden erhoben (Herstellerinfos, CVE, Scans BL-OPS-02), betroffene Systeme identifiziert, das Risiko bewertet und nach BL-OPS-01 risikoorientiert über Patch-/Change-Management (siehe {{LINK:VA-06}}) behandelt (kritisch {{PATCH_SLA_CRIT}}); die erfolgreiche Installation wird verifiziert und im {{TOOL_TICKET}} nachverfolgt, risikominimierende Maßnahmen greifen bei Bedarf.") + +DATA["5.2.6"] = dict(policy="R10", title="Technische Überprüfung von IT-Systemen", + must=[ + "Anforderungen an die Prüfung (Audit) von IT-Systemen oder -Diensten sind bestimmt.", + "Der Umfang der Systemprüfung wird rechtzeitig festgelegt.", + "System- oder Dienstprüfungen werden mit Betreiber und Nutzern der IT-Systeme/-Dienste abgestimmt.", + "Die Ergebnisse von System-/Dienstprüfungen werden nachvollziehbar gespeichert und der zuständigen Leitung berichtet.", + "Aus den Ergebnissen werden Maßnahmen abgeleitet und in angemessener Frist umgesetzt.", + ], should=[ + "System- und Dienstprüfungen werden unter Berücksichtigung möglicher Sicherheitsrisiken (z. B. Störungen) geplant.", + "Regelmäßige System- oder Dienstprüfungen werden durchgeführt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Innerhalb einer angemessenen Frist nach Abschluss der Prüfung wird ein Bericht erstellt.", + ], high=[ + "Für kritische IT-Systeme/-Dienste wurden zusätzliche Prüfanforderungen identifiziert und werden erfüllt (z. B. dienstspezifische Tests/Werkzeuge und/oder manuelle Penetrationstests, risikobasierte Intervalle). (A)", + ], vhigh=[ + "IT-Systeme und -Dienste werden regelmäßig auf Schwachstellen gescannt. Für nicht scanbare Systeme/Dienste sind geeignete Schutzmaßnahmen umzusetzen. (C, I, A)", + ], + impl="Anforderungen und Umfang technischer Prüfungen sind bestimmt und mit Betreibern/Nutzern abgestimmt; Systeme werden nach Härtungsvorgaben (BL-OPS-07, z. B. CIS-Benchmarks) konfiguriert und risikoorientiert geprüft. Ergebnisse werden nachvollziehbar gespeichert, der Leitung berichtet und Maßnahmen fristgerecht umgesetzt.", + impl_elev="Bei hohem Schutzbedarf werden für kritische Systeme zusätzliche Prüfungen (Penetrationstests {{PENTEST_FREQ}}, BL-OPS-08) durchgeführt. Bei sehr hohem Schutzbedarf werden Systeme regelmäßig auf Schwachstellen gescannt bzw. nicht scanbare durch geeignete Maßnahmen geschützt.") + +DATA["5.2.7"] = dict(policy="R10", title="Netzwerksicherheit", + must=[ + "Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und erfüllt.", + "Anforderungen an die Netzsegmentierung sind bestimmt und erfüllt.", + ], should=[ + "Verfahren für das Management und die Steuerung von Netzwerken sind definiert.", + "Für eine risikobasierte Netzsegmentierung werden die einschlägigen Aspekte berücksichtigt.", + ], high=[ + "Erweiterte Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und umgesetzt. (C, I, A)", + ], vhigh=[], + impl="Das Netzwerk ist nach Schutzbedarf risikobasiert segmentiert (BL-NET-01), zugangskontrolliert und nach außen über Firewall (Default-Deny, BL-NET-02) abgesichert; Management-/Steuerungsverfahren und ein aktueller Netzplan/Segmentierungskonzept werden gepflegt.{{#if FLAG_OT_USED}} Produktions-/OT-Netze sind von Office-Netzen getrennt und besonders abgesichert.{{/if}}", + impl_elev="Bei hohem Schutzbedarf sind erweiterte Anforderungen an Netzmanagement und -steuerung bestimmt und umgesetzt.") + +DATA["5.2.8"] = dict(policy="R04", title="Kontinuitätsplanung für IT-Dienste", + must=[ + "Kritische IT-Dienste sind identifiziert und die Geschäftsauswirkung wird berücksichtigt.", + "Anforderungen und Verantwortlichkeiten für Kontinuität und Wiederherstellung dieser IT-Dienste sind relevanten Stakeholdern bekannt und erfüllt.", + ], should=[ + "Kritische IT-Systeme sind identifiziert; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Eine Kontinuitätsplanung existiert und wird regelmäßig überprüft und aktualisiert.", + "Die Kontinuitätsplanung umfasst mindestens (D)DoS-Angriffe, erfolgreiche Ransomware-Angriffe und andere Sabotage, Systemausfallszenarien sowie Naturkatastrophen, die kritische IT-Systeme betreffen.", + ], high=[ + "Die Kontinuitätsplanung enthält vordefinierte Zeitrahmen (Recovery Time Objective) für die Wiederaufnahme des Betriebs. (A)", + "Angemessene SLAs mit externen Dienstleistern entsprechend der Kontinuitätsplanung bestehen. (A)", + "Die Kontinuitätspläne umfassen die Koordination vertraglich vereinbarter Kommunikation mit Geschäftspartnern. (A)", + "Die Kontinuitätsplanung wird regelmäßig getestet, inkl. vollständiger Wiederherstellung in einen bekannten Zustand und Einhaltung definierter Zielzeiten. (A)", + "Eine Backup- und Wiederherstellungsstrategie für kritische IT-Dienste und Informationen ist definiert und umgesetzt. (C, I, A)", + "Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugte Veränderung/Löschung durch Schadsoftware geschützt. (I, A)", + "Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugten Zugriff durch Schadsoftware oder Betreiber geschützt. (C, I)", + ], vhigh=[ + "Die Kontinuitätsplanung ist mit den Kontinuitätsplänen relevanter externer Dienstleister abgestimmt. (A)", + "Die Fortführung wesentlicher Kern- und Geschäftsfunktionen mit minimalem oder keinem Verlust an Betriebskontinuität ist möglich; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Die Kontinuitätsplanung wird regelmäßig getestet. Testszenarien, Ergebnisse und Lessons Learned werden aufgezeichnet. (I, A)", + ], + impl="Kritische IT-Dienste sind mit Geschäftsauswirkung identifiziert; Anforderungen und Verantwortlichkeiten für Kontinuität/Wiederherstellung sind bekannt und erfüllt. Eine Kontinuitätsplanung (inkl. (D)DoS, Ransomware, Ausfall, Naturkatastrophen) besteht, wird regelmäßig überprüft und über das IT-Notfallverfahren umgesetzt (siehe {{LINK:VA-02}}).", + impl_elev="Bei hohem Schutzbedarf sind RTO/RPO, SLAs mit Dienstleistern, Partnerkommunikation, regelmäßige Volltests sowie eine geschützte Backup-/Recovery-Strategie (immutable/isoliert) etabliert. Bei sehr hohem Schutzbedarf ist die Planung mit externen Dienstleistern abgestimmt, die Fortführung wesentlicher Funktionen sichergestellt und Tests inkl. Lessons Learned werden aufgezeichnet.") + +DATA["5.2.9"] = dict(policy="R10", title="Datensicherung und Wiederherstellung", + must=[ + "Backup-Konzepte existieren für relevante IT-Systeme. Angemessene Schutzmaßnahmen für Vertraulichkeit, Integrität und Verfügbarkeit der Datensicherungen werden berücksichtigt.", + "Wiederherstellungskonzepte existieren für relevante IT-Dienste.", + ], should=[ + "Für jeden relevanten IT-Dienst existiert ein Backup- und Wiederherstellungskonzept. Abhängigkeiten zwischen IT-Diensten und die Reihenfolge der Wiederherstellung werden berücksichtigt.", + ], high=[ + "Backup- und Wiederherstellungskonzepte werden methodisch in regelmäßigen Abständen überprüft. (A)", + "Die grundsätzliche Wiederherstellbarkeit wird berücksichtigt und getestet (z. B. Stichprobentests, Testsysteme). (I, A)", + ], vhigh=[ + "(Zusätzliche) Backups werden über Offline-Verfahren, unveränderliche (immutable) Backups oder eine isolierte IAM-Lösung durchgeführt. (I, A)", + "Wiederherstellungsverfahren werden methodisch in regelmäßigen Abständen technisch getestet. (I, A)", + "Geografische Redundanz wird in Backup- und Wiederherstellungskonzepten berücksichtigt. (A)", + ], + impl="Backup- und Wiederherstellungskonzepte für relevante IT-Dienste bestehen (Schutz von Vertraulichkeit/Integrität/Verfügbarkeit, Abhängigkeiten und Reihenfolge berücksichtigt); Sicherung erfolgt nach Schema {{BACKUP_SCHEME}} über {{TECH_BACKUP}} (BL-OPS-05), Aufbewahrung {{BACKUP_RETENTION}}, Wiederherstellung geregelt und getestet (siehe {{LINK:VA-05}}).", + impl_elev="Bei hohem Schutzbedarf werden Konzepte methodisch überprüft und die Wiederherstellbarkeit getestet. Bei sehr hohem Schutzbedarf erfolgen zusätzliche Offline-/immutable-Backups, methodische technische Restore-Tests und geografische Redundanz.") + +DATA["5.3.1"] = dict(policy="R11", title="Sicherheit bei Beschaffung und Entwicklung", + must=[ + "Die mit Design und Entwicklung eines IT-Dienstes verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt.", + "Die mit Beschaffung oder Erweiterung von IT-Diensten und -Komponenten verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt.", + "Informationssicherheitsanforderungen im Zusammenhang mit Änderungen an entwickelten IT-Diensten werden berücksichtigt.", + "Systemabnahmetests werden unter Berücksichtigung der Informationssicherheitsanforderungen durchgeführt.", + ], should=[ + "Anforderungsspezifikationen werden erstellt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "Anforderungsspezifikationen werden gegen die Informationssicherheitsanforderungen geprüft.", + "Der IT-Dienst wird vor Produktivnutzung auf Einhaltung der Spezifikationen geprüft.", + "Die Nutzung von Produktivdaten zu Testzwecken wird soweit möglich vermieden (ggf. Anonymisierung/Pseudonymisierung); dabei werden die einschlägigen Aspekte berücksichtigt.", + "Testsysteme erhalten Schutzmaßnahmen vergleichbar zur Produktivumgebung, wenn Produktivdaten für Tests genutzt werden.", + ], high=[], vhigh=[ + "Die Sicherheit zweckgebauter oder wesentlich angepasster Software wird bei Inbetriebnahme, bei wesentlichen Änderungen oder regelmäßig getestet (z. B. Penetrationstest). (C, I, A)", + ], + impl="Informationssicherheitsanforderungen sind fester Bestandteil von Design, Beschaffung, Erweiterung und Änderung von IT-Diensten (Security by Design); Anforderungsspezifikationen werden erstellt und geprüft, Abnahmetests unter Sicherheitsaspekten durchgeführt, Produktivsetzung erst nach Prüfung im {{TOOL_TICKET}}. Produktivdaten in Tests werden vermieden/anonymisiert, Testsysteme angemessen geschützt.{{#if FLAG_DEV_INHOUSE}} Für die Eigenentwicklung gelten Secure-Coding-Vorgaben mit Code-Reviews und automatisierten Sicherheitstests (SAST/Dependency-Scan).{{/if}}", + impl_elev="Bei sehr hohem Schutzbedarf wird die Sicherheit zweckgebauter oder wesentlich angepasster Software bei Inbetriebnahme, bei wesentlichen Änderungen oder regelmäßig getestet (Penetrationstest).") + +DATA["5.3.2"] = dict(policy="R11", title="Anforderungen an Netzdienste", + must=[ + "Anforderungen an die Informationssicherheit von Netzdiensten sind bestimmt und erfüllt.", + ], should=[ + "Ein Verfahren zur Absicherung und Nutzung von Netzdiensten ist definiert und umgesetzt.", + "Die Anforderungen werden in Form von SLAs vereinbart.", + "Angemessene Redundanzlösungen sind umgesetzt.", + ], high=[ + "Verfahren zur Überwachung der Qualität des Netzverkehrs (z. B. Traffic-Flow-Analysen, Verfügbarkeitsmessungen) sind definiert und werden durchgeführt. (A)", + ], vhigh=[], + impl="Für genutzte Netzdienste (intern/extern) sind Sicherheitsanforderungen bestimmt, in SLAs vereinbart und über ein Verfahren umgesetzt; angemessene Redundanzen bestehen.", + impl_elev="Bei hohem Schutzbedarf werden Verfahren zur Überwachung der Netzverkehrsqualität (Traffic-Flow-Analysen, Verfügbarkeitsmessungen) definiert und durchgeführt.") + +DATA["5.3.3"] = dict(policy="R11", title="Rückgabe und sichere Löschung", + must=[], should=[ + "Eine Beschreibung des Beendigungsprozesses ist vorhanden, an Änderungen angepasst und vertraglich geregelt.", + ], high=[], vhigh=[], + impl="Rückgabe und sichere Löschung/Vernichtung von Informationen und Assets (bei Vertragsende, Geräteausmusterung) sind nach BL-DEL-01 geregelt, vertraglich vereinbart, an Änderungen angepasst und werden nachgewiesen (Löschprotokoll).") + +DATA["5.3.4"] = dict(policy="R12", title="Schutz in geteilten externen IT-Diensten", + must=[ + "Eine wirksame Trennung (z. B. Mandantentrennung) verhindert den Zugriff unbefugter Nutzer anderer Organisationen auf eigene Informationen.", + ], should=[ + "Das Trennungskonzept des Anbieters ist dokumentiert und an Änderungen angepasst; dabei werden die einschlägigen Aspekte berücksichtigt.", + ], high=[], vhigh=[], + impl="Bei geteilten externen IT-Diensten wird eine wirksame Mandantentrennung gefordert und vertraglich zugesichert; das Trennungskonzept des Anbieters wird dokumentiert und bei Änderungen aktualisiert.{{#if FLAG_CLOUD_USED}} Cloud-Dienste werden vor Nutzung bewertet (Schutzbedarf, Datenlokation/EU, Verschlüsselung, Exit) und von {{ROLE_ISB}} freigegeben; die Freigabeliste wird im ISMS-Tool ({{TOOL_NAME}}) geführt (siehe {{LINK:VA-11}}).{{/if}}") + +DATA["6.1.1"] = dict(policy="R13", title="Informationssicherheit bei Lieferanten", + must=[ + "Auftragnehmer und Partner werden einer Sicherheitsrisikobewertung unterzogen.", + "Ein angemessenes Informationssicherheitsniveau wird durch vertragliche Vereinbarungen mit Auftragnehmern und Partnern sichergestellt.", + "Sofern zutreffend, werden vertragliche Vereinbarungen mit Auftraggebern/Kunden an Auftragnehmer und Partner weitergegeben.", + ], should=[ + "Auftragnehmer und Partner sind vertraglich verpflichtet, Anforderungen an ein angemessenes Informationssicherheitsniveau an ihre Unterauftragnehmer weiterzugeben.", + "Leistungsberichte und Dokumente von Auftragnehmern und Partnern werden geprüft.", + ], high=[ + "Es wird nachgewiesen, dass das Informationssicherheitsniveau des Lieferanten dem Schutzbedarf angemessen ist (z. B. geprüfter Fragebogen/Selbstauskunft, Attestierung, Zertifikat, Lieferantenaudit). (C, I, A)", + "Der Grad der Erfüllung geforderter Nachweise durch den Lieferanten wird dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. (C, I, A)", + "Die Einhaltung vertraglicher Vereinbarungen durch den Lieferanten wird geprüft, dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. (C, I, A)", + ], vhigh=[ + "Das angemessene Informationssicherheitsniveau sollte durch ein Drittparteien-Audit (angemessenes TISAX-Label o. Ä.) oder ein angemessenes Lieferantenaudit nachgewiesen werden. Ohne Audit muss die Leitung eine risikobasierte Entscheidung zur Fortführung treffen; ein Nachweis dieser Entscheidung existiert. (C, I, A)", + "Vertragliche Verpflichtungen gegenüber Kunden zur Transparenz von Lieferkettenrisiken werden erfüllt. (C, I, A)", + ], + impl="Auftragnehmer/Partner werden einer Sicherheitsrisikobewertung (BL-SUP-01) unterzogen und vertraglich auf ein angemessenes Informationssicherheitsniveau (inkl. Weitergabe an Unterauftragnehmer und Kundenanforderungen) verpflichtet; das Lieferantenverzeichnis wird im ISMS-Tool ({{TOOL_NAME}}) geführt, Leistungsberichte werden geprüft (siehe {{LINK:VA-10}}).", + impl_elev="Bei hohem Schutzbedarf wird das Sicherheitsniveau des Lieferanten nachgewiesen (Selbstauskunft/Attest/Zertifikat/Audit) und die Einhaltung dokumentiert, regelmäßig und bei Änderungen überwacht. Bei sehr hohem Schutzbedarf erfolgt der Nachweis über ein Drittparteien-Audit (TISAX o. Ä.) oder eine dokumentierte risikobasierte Leitungsentscheidung; Transparenzpflichten zu Lieferkettenrisiken werden erfüllt.") + +DATA["6.1.2"] = dict(policy="R13", title="Vertraulichkeitsvereinbarungen", + must=[ + "Die Vertraulichkeitsanforderungen sind bestimmt und erfüllt.", + "Anforderungen und Verfahren zur Anwendung von Vertraulichkeitsvereinbarungen sind allen Personen bekannt, die schutzbedürftige Informationen weitergeben.", + "Gültige Vertraulichkeitsvereinbarungen werden vor der Weitergabe schutzbedürftiger Informationen abgeschlossen.", + "Die Anforderungen und Verfahren zur Nutzung von Vertraulichkeitsvereinbarungen und zum Umgang mit schutzbedürftigen Informationen werden regelmäßig überprüft.", + ], should=[ + "Vorlagen für Vertraulichkeitsvereinbarungen sind vorhanden und auf rechtliche Anwendbarkeit geprüft.", + "Vertraulichkeitsvereinbarungen umfassen beteiligte Personen/Organisationen, Art der Informationen, Gegenstand, Gültigkeitsdauer und Verantwortlichkeiten der verpflichteten Partei.", + "Vertraulichkeitsvereinbarungen enthalten Regelungen zum Umgang mit schutzbedürftigen Informationen über die Vertragsbeziehung hinaus.", + "Möglichkeiten zum Nachweis der Einhaltung (z. B. Prüfung durch unabhängige Dritte oder Auditrechte) sind definiert.", + "Ein Prozess zur Überwachung der Gültigkeitsdauer temporärer Vertraulichkeitsvereinbarungen und zur rechtzeitigen Verlängerung ist definiert und umgesetzt.", + ], high=[], vhigh=[], + impl="Vertraulichkeitsanforderungen sind bestimmt und bekannt; vor Weitergabe schutzbedürftiger Informationen werden gültige NDAs auf Basis geprüfter Standardvorlagen (mit Parteien, Informationsart, Gegenstand, Gültigkeit, Verantwortlichkeiten und nachvertraglichen Regelungen) abgeschlossen und im ISMS-Tool hinterlegt. Anforderungen/Verfahren und Gültigkeitsdauern werden regelmäßig überwacht, Nachweismöglichkeiten sind definiert.") + +DATA["6.1.3"] = dict(policy="R13", title="Abgrenzung der Verantwortlichkeiten", + must=[ + "Die betroffenen IT-Dienste sind identifiziert.", + "Die für den IT-Dienst relevanten Sicherheitsanforderungen sind bestimmt.", + "Die für die Umsetzung der Anforderung verantwortliche Organisation ist definiert und sich ihrer Verantwortung bewusst.", + "Mechanismen für geteilte Verantwortlichkeiten sind spezifiziert und umgesetzt.", + "Die verantwortliche Organisation erfüllt ihre jeweiligen Verantwortlichkeiten.", + ], should=[ + "Bei IT-Diensten ist die Konfiguration auf Basis der notwendigen Sicherheitsanforderungen konzipiert, umgesetzt und dokumentiert.", + "Das verantwortliche Personal ist angemessen geschult.", + ], high=[ + "Eine Liste der betroffenen IT-Dienste und der jeweils verantwortlichen IT-Dienstleister existiert. (C, I, A)", + "Die Anwendbarkeit der ISA-Controls wurde bewertet und dokumentiert. (C, I, A)", + "Die Dienstkonfiguration ist in die regelmäßigen Sicherheitsbewertungen einbezogen. (C, I, A)", + "Es wird nachgewiesen, dass die IT-Dienstleister ihre Verantwortung erfüllen. (C, I, A)", + "Die Integration in lokale Schutzmaßnahmen (z. B. sichere Authentifizierungsmechanismen) ist etabliert und dokumentiert. (C, I, A)", + ], vhigh=[], + impl="Betroffene IT-Dienste und ihre Sicherheitsanforderungen sind identifiziert; Verantwortlichkeiten zwischen der Organisation und externen IT-Dienstleistern (inkl. Mechanismen für geteilte Verantwortung) sind definiert, bekannt und werden erfüllt. Die Konfiguration ist anforderungsbasiert umgesetzt und dokumentiert, das Personal geschult.", + impl_elev="Bei hohem Schutzbedarf existiert eine Liste der IT-Dienste und verantwortlichen Dienstleister, die Anwendbarkeit der ISA-Controls ist bewertet/dokumentiert, die Dienstkonfiguration ist Teil regelmäßiger Sicherheitsbewertungen, die Verantwortungserfüllung wird nachgewiesen und die Integration in lokale Schutzmaßnahmen ist dokumentiert.") + +DATA["7.1.1"] = dict(policy="R14", title="Regulatorische und vertragliche Compliance", + must=[ + "Rechtliche, regulatorische und vertragliche Vorgaben mit Relevanz für die Informationssicherheit werden regelmäßig bestimmt.", + "Richtlinien zur Einhaltung der Vorgaben sind definiert, umgesetzt und den verantwortlichen Personen kommuniziert.", + ], should=[ + "Die Integrität von Aufzeichnungen entsprechend rechtlichen, regulatorischen und vertraglichen Vorgaben sowie Geschäftsanforderungen wird berücksichtigt.", + ], high=[], vhigh=[], + impl="Relevante rechtliche, regulatorische und vertragliche Anforderungen werden regelmäßig bestimmt und in einem Compliance-/Rechtsregister im ISMS-Tool ({{TOOL_NAME}}) erfasst; Richtlinien zur Einhaltung sind definiert, umgesetzt und den Verantwortlichen kommuniziert, die Integrität von Aufzeichnungen wird berücksichtigt.") + +DATA["7.1.2"] = dict(policy="R14", title="Schutz personenbezogener Daten", + must=[ + "Rechtliche und vertragliche Informationssicherheitsanforderungen an Verfahren und Prozesse bei der Verarbeitung personenbezogener Daten sind bestimmt.", + "Regelungen zur Einhaltung rechtlicher und vertraglicher Anforderungen an den Schutz personenbezogener Daten sind definiert und den beteiligten Personen bekannt.", + "Prozesse und Verfahren zum Schutz personenbezogener Daten sind im Informationssicherheits-Managementsystem berücksichtigt.", + ], should=[], high=[], vhigh=[], + flag="FLAG_PERSONAL_DATA", + impl="Rechtliche und vertragliche Anforderungen an die Verarbeitung personenbezogener Daten (DSGVO) sind bestimmt; Regelungen sind definiert, den Beteiligten bekannt und im ISMS berücksichtigt. {{ROLE_DPO}} ist eingebunden, das Verzeichnis der Verarbeitungstätigkeiten wird im ISMS-Tool ({{TOOL_NAME}}) geführt, TOM und Löschkonzepte (BL-DEL-01) sind geregelt.") + +# ---- Nicht-ISA-Zusatz (kundenspezifisch): KI-/GenAI-Nutzung, an R12 angehaengt ---- +CUSTOM = {} +CUSTOM["5.3.4-KI"] = dict(policy="R12", title="Nutzung von KI-/GenAI-Diensten", flag="FLAG_AI_USED", + must=[ + "Der Einsatz von KI-/GenAI-Diensten ist geregelt; es werden nur freigegebene Dienste genutzt.", + "Die Eingabe vertraulicher oder personenbezogener Informationen in nicht freigegebene KI-Dienste ist untersagt; zulässige Datenklassen je Dienst sind definiert.", + "Bei freigegebenen KI-Diensten ist geklärt und vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden.", + ], should=[ + "Ergebnisse von KI-Diensten werden vor geschäftskritischer Verwendung geprüft (Human-in-the-Loop); der KI-Einsatz wird dokumentiert und regulatorische Anforderungen (z. B. EU AI Act) berücksichtigt.", + ], high=[], vhigh=[], + impl="Der Einsatz von KI-/GenAI-Diensten ist geregelt; nur von {{ROLE_ISB}} freigegebene Dienste (Freigabeliste im ISMS-Tool) dürfen genutzt werden (siehe {{LINK:VA-11}}). Zulässige Datenklassen je Dienst sind definiert, die Eingabe vertraulicher/personenbezogener Daten in nicht freigegebene Dienste ist untersagt; bei Freigabe ist vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden. KI-Ergebnisse werden vor kritischer Verwendung geprüft (Human-in-the-Loop), der Einsatz dokumentiert und der EU AI Act berücksichtigt.") + diff --git a/seed/isms-vorlagenpaket-v2/_iso_crosswalk.json b/seed/isms-vorlagenpaket-v2/_iso_crosswalk.json new file mode 100644 index 0000000..e54b97e --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_iso_crosswalk.json @@ -0,0 +1,1735 @@ +{ + "meta": { + "quelle": "ISO27001-Vorlagenpaket-final (Paraphrasen)", + "ziel": "isms-vorlagenpaket-v2", + "erstellt": "2026-08-21" + }, + "zuordnung": [ + { + "id": "4.1-1", + "ref": "4.1", + "kind": "clause", + "title": "Verstehen der Organisation und ihres Kontexts", + "policy": "R01", + "section": "ISO-MS-KONTEXT", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Interne und externe Themen, die die Fähigkeit zur Erreichung der ISMS-Ziele beeinflussen, sind zu bestimmen und aktuell zu halten." + }, + { + "id": "4.2-1", + "ref": "4.2", + "kind": "clause", + "title": "Anforderungen interessierter Parteien", + "policy": "R01", + "section": "ISO-MS-KONTEXT", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Die für das ISMS relevanten interessierten Parteien und deren Anforderungen an die Informationssicherheit sind zu ermitteln." + }, + { + "id": "4.3-1", + "ref": "4.3", + "kind": "clause", + "title": "Anwendungsbereich des ISMS", + "policy": "R01", + "section": "ISO-MS-KONTEXT", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Der Anwendungsbereich des ISMS ist unter Berücksichtigung der Themen, Anforderungen und Schnittstellen festzulegen und als dokumentierte Information zu führen." + }, + { + "id": "4.4-1", + "ref": "4.4", + "kind": "clause", + "title": "Informationssicherheits-Managementsystem", + "policy": "R01", + "section": "ISO-MS-KONTEXT", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Ein ISMS ist einzurichten, umzusetzen, aufrechtzuerhalten und fortlaufend zu verbessern." + }, + { + "id": "5.1-1", + "ref": "5.1", + "kind": "clause", + "title": "Führung und Verpflichtung", + "policy": "R01", + "section": "1.2.1", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Die oberste Leitung hat Führung und Verpflichtung in Bezug auf das ISMS nachzuweisen." + }, + { + "id": "5.2-1", + "ref": "5.2", + "kind": "clause", + "title": "Politik", + "policy": "L00", + "section": "ISO-LEITLINIE", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Die oberste Leitung hat eine Informationssicherheitspolitik festzulegen, die zum Zweck der Organisation passt und Ziele bzw. einen Rahmen dafür enthält." + }, + { + "id": "5.3-1", + "ref": "5.3", + "kind": "clause", + "title": "Rollen, Verantwortlichkeiten und Befugnisse", + "policy": "R01", + "section": "1.2.2", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Verantwortlichkeiten und Befugnisse für sicherheitsrelevante Rollen sind zuzuweisen und bekannt zu machen." + }, + { + "id": "6.1.1-1", + "ref": "6.1.1", + "kind": "clause", + "title": "Maßnahmen zum Umgang mit Risiken und Chancen", + "policy": "R03", + "section": "1.4.1", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-09" + ], + "requirement": "Bei der Planung des ISMS sind Risiken und Chancen zu bestimmen, die zu behandeln sind." + }, + { + "id": "6.1.2-1", + "ref": "6.1.2", + "kind": "clause", + "title": "Informationssicherheits-Risikobeurteilung", + "policy": "R03", + "section": "1.4.1", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-09" + ], + "requirement": "Ein Prozess zur Risikobeurteilung mit definierten Kriterien, Wiederholbarkeit und vergleichbaren Ergebnissen ist festzulegen und anzuwenden." + }, + { + "id": "6.1.3-1", + "ref": "6.1.3", + "kind": "clause", + "title": "Informationssicherheits-Risikobehandlung", + "policy": "R03", + "section": "ISO-SOA", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-09" + ], + "requirement": "Ein Risikobehandlungsprozess ist festzulegen; erforderliche Controls sind zu bestimmen und mit Annex A abzugleichen (Statement of Applicability)." + }, + { + "id": "6.2-1", + "ref": "6.2", + "kind": "clause", + "title": "Informationssicherheitsziele und Planung", + "policy": "L00", + "section": "ISO-LEITLINIE", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Informationssicherheitsziele sind für relevante Funktionen und Ebenen festzulegen und deren Erreichung zu planen." + }, + { + "id": "6.3-1", + "ref": "6.3", + "kind": "clause", + "title": "Planung von Änderungen", + "policy": "R01", + "section": "ISO-MS-CHANGE", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Änderungen am ISMS sind geplant durchzuführen." + }, + { + "id": "7.1-1", + "ref": "7.1", + "kind": "clause", + "title": "Ressourcen", + "policy": "R01", + "section": "1.2.2", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Die für das ISMS erforderlichen Ressourcen sind zu bestimmen und bereitzustellen." + }, + { + "id": "7.2-1", + "ref": "7.2", + "kind": "clause", + "title": "Kompetenz", + "policy": "R05", + "section": "2.1.1", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Erforderliche Kompetenzen sind zu bestimmen und sicherzustellen; entsprechende Nachweise sind zu führen." + }, + { + "id": "7.3-1", + "ref": "7.3", + "kind": "clause", + "title": "Bewusstsein", + "policy": "R05", + "section": "2.1.3", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-12" + ], + "requirement": "Personen unter Aufsicht der Organisation müssen sich der Politik, ihres Beitrags und der Folgen von Verstößen bewusst sein." + }, + { + "id": "7.4-1", + "ref": "7.4", + "kind": "clause", + "title": "Kommunikation", + "policy": "L00", + "section": "ISO-LEITLINIE", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Die für das ISMS relevante interne und externe Kommunikation ist zu bestimmen." + }, + { + "id": "7.5.1-1", + "ref": "7.5.1", + "kind": "clause", + "title": "Dokumentierte Information – Allgemeines", + "policy": "R01", + "section": "ISO-MS-DOKU", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Das ISMS muss die von der Norm geforderte und die als notwendig bestimmte dokumentierte Information enthalten." + }, + { + "id": "7.5.2-1", + "ref": "7.5.2", + "kind": "clause", + "title": "Erstellen und Aktualisieren", + "policy": "R01", + "section": "ISO-MS-DOKU", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Bei Erstellung und Aktualisierung dokumentierter Information sind Kennzeichnung, Format/Medium und Prüfung/Freigabe sicherzustellen." + }, + { + "id": "7.5.3-1", + "ref": "7.5.3", + "kind": "clause", + "title": "Lenkung dokumentierter Information", + "policy": "R01", + "section": "ISO-MS-DOKU", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Dokumentierte Information ist zu lenken (Verfügbarkeit, Schutz, Verteilung, Zugriff, Aufbewahrung, Änderungssteuerung)." + }, + { + "id": "8.1-1", + "ref": "8.1", + "kind": "clause", + "title": "Betriebliche Planung und Steuerung", + "policy": "R03", + "section": "ISO-MS-BETRIEB", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [], + "requirement": "Die zur Erfüllung der Anforderungen nötigen Prozesse sind zu planen, umzusetzen und zu steuern; geplante Änderungen sind zu kontrollieren." + }, + { + "id": "8.2-1", + "ref": "8.2", + "kind": "clause", + "title": "Informationssicherheits-Risikobeurteilung (Durchführung)", + "policy": "R03", + "section": "1.4.1", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-09" + ], + "requirement": "Risikobeurteilungen sind in geplanten Abständen und bei wesentlichen Änderungen durchzuführen und zu dokumentieren." + }, + { + "id": "8.3-1", + "ref": "8.3", + "kind": "clause", + "title": "Informationssicherheits-Risikobehandlung (Durchführung)", + "policy": "R03", + "section": "1.4.1", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-09" + ], + "requirement": "Der Risikobehandlungsplan ist umzusetzen; die Ergebnisse sind zu dokumentieren." + }, + { + "id": "9.1-1", + "ref": "9.1", + "kind": "clause", + "title": "Überwachung, Messung, Analyse und Bewertung", + "policy": "R03", + "section": "ISO-MS-MESSUNG", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-22" + ], + "requirement": "Die Informationssicherheitsleistung und die Wirksamkeit des ISMS sind zu überwachen, zu messen, zu analysieren und zu bewerten." + }, + { + "id": "9.2-1", + "ref": "9.2", + "kind": "clause", + "title": "Internes Audit", + "policy": "R03", + "section": "1.5.2", + "new_section": false, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-15" + ], + "requirement": "Interne Audits sind in geplanten Abständen durchzuführen, um die Konformität und wirksame Umsetzung des ISMS zu prüfen." + }, + { + "id": "9.3-1", + "ref": "9.3", + "kind": "clause", + "title": "Managementbewertung", + "policy": "R03", + "section": "ISO-MS-MGMTREVIEW", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-22" + ], + "requirement": "Die oberste Leitung hat das ISMS in geplanten Abständen zu bewerten (Managementbewertung)." + }, + { + "id": "10.1-1", + "ref": "10.1", + "kind": "clause", + "title": "Fortlaufende Verbesserung", + "policy": "R03", + "section": "ISO-MS-CAPA", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-21" + ], + "requirement": "Die Eignung, Angemessenheit und Wirksamkeit des ISMS ist fortlaufend zu verbessern." + }, + { + "id": "10.2-1", + "ref": "10.2", + "kind": "clause", + "title": "Nichtkonformität und Korrekturmaßnahmen", + "policy": "R03", + "section": "ISO-MS-CAPA", + "new_section": true, + "condition": null, + "soa_relevant": false, + "verfahren": [ + "VA-21" + ], + "requirement": "Bei Nichtkonformitäten sind Korrekturen vorzunehmen und Korrekturmaßnahmen zur Beseitigung der Ursachen zu ergreifen." + }, + { + "id": "A.5.1-1", + "ref": "A.5.1", + "kind": "control", + "title": "Informationssicherheitsrichtlinien", + "policy": "L00", + "section": "ISO-LEITLINIE", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Ein Satz von Informationssicherheitsrichtlinien ist zu definieren, von der Leitung zu genehmigen, zu veröffentlichen, zu kommunizieren und regelmäßig sowie anlassbezogen zu überprüfen." + }, + { + "id": "A.5.2-1", + "ref": "A.5.2", + "kind": "control", + "title": "Rollen und Verantwortlichkeiten", + "policy": "R01", + "section": "1.2.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Rollen und Verantwortlichkeiten für die Informationssicherheit sind zu definieren und zuzuweisen." + }, + { + "id": "A.5.3-1", + "ref": "A.5.3", + "kind": "control", + "title": "Aufgabentrennung", + "policy": "R01", + "section": "1.2.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Widerstreitende Aufgaben und Verantwortungsbereiche sind zu trennen, um unbefugte oder unbeabsichtigte Änderungen und Missbrauch zu reduzieren." + }, + { + "id": "A.5.4-1", + "ref": "A.5.4", + "kind": "control", + "title": "Verantwortung der Leitung", + "policy": "R01", + "section": "1.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Die Leitung hat von allen Beschäftigten die Anwendung der Informationssicherheit gemäß den festgelegten Vorgaben einzufordern." + }, + { + "id": "A.5.5-1", + "ref": "A.5.5", + "kind": "control", + "title": "Kontakt mit Behörden", + "policy": "R01", + "section": "ISO-KONTAKTE", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Angemessene Kontakte zu relevanten Behörden sind einzurichten und zu pflegen." + }, + { + "id": "A.5.6-1", + "ref": "A.5.6", + "kind": "control", + "title": "Kontakt mit speziellen Interessengruppen", + "policy": "R01", + "section": "ISO-KONTAKTE", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Angemessene Kontakte zu speziellen Interessengruppen, Fachforen und Sicherheitsverbänden sind zu pflegen." + }, + { + "id": "A.5.7-1", + "ref": "A.5.7", + "kind": "control", + "title": "Bedrohungsinformationen", + "policy": "R10", + "section": "ISO-THREATINTEL", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Informationen über Bedrohungen sind zu sammeln und auszuwerten, um Bedrohungsinformationen (Threat Intelligence) zu erzeugen und zu nutzen." + }, + { + "id": "A.5.8-1", + "ref": "A.5.8", + "kind": "control", + "title": "Informationssicherheit im Projektmanagement", + "policy": "R01", + "section": "1.2.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-19" + ], + "requirement": "Informationssicherheit ist in das Projektmanagement zu integrieren." + }, + { + "id": "A.5.9-1", + "ref": "A.5.9", + "kind": "control", + "title": "Inventar der Informationen und Assets", + "policy": "R02", + "section": "1.3.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Ein Inventar der Informationen und zugehörigen Assets einschließlich Eigentümer ist zu erstellen und zu pflegen." + }, + { + "id": "A.5.10-1", + "ref": "A.5.10", + "kind": "control", + "title": "Zulässige Nutzung von Informationen und Assets", + "policy": "R02", + "section": "1.3.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Regeln zur zulässigen Nutzung und zum Umgang mit Informationen und Assets sind festzulegen, zu dokumentieren und umzusetzen." + }, + { + "id": "A.5.11-1", + "ref": "A.5.11", + "kind": "control", + "title": "Rückgabe von Assets", + "policy": "R11", + "section": "5.3.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Beschäftigte und externe Nutzer haben bei Beendigung des Beschäftigungs-/Vertragsverhältnisses alle in ihrem Besitz befindlichen Assets zurückzugeben." + }, + { + "id": "A.5.12-1", + "ref": "A.5.12", + "kind": "control", + "title": "Klassifizierung von Informationen", + "policy": "R02", + "section": "1.3.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Informationen sind entsprechend ihrem Schutzbedarf (Vertraulichkeit, Integrität, Verfügbarkeit) zu klassifizieren." + }, + { + "id": "A.5.13-1", + "ref": "A.5.13", + "kind": "control", + "title": "Kennzeichnung von Informationen", + "policy": "R02", + "section": "1.3.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Verfahren zur Kennzeichnung von Informationen gemäß dem Klassifizierungsschema sind zu entwickeln und umzusetzen." + }, + { + "id": "A.5.14-1", + "ref": "A.5.14", + "kind": "control", + "title": "Informationsübertragung", + "policy": "R09", + "section": "5.1.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Regeln, Verfahren und Vereinbarungen zur sicheren Übertragung von Informationen für alle genutzten Übertragungswege sind festzulegen." + }, + { + "id": "A.5.15-1", + "ref": "A.5.15", + "kind": "control", + "title": "Zugangssteuerung", + "policy": "R08", + "section": "4.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Regeln zur Steuerung des physischen und logischen Zugriffs auf Informationen und Assets sind auf Basis der Geschäfts- und Informationssicherheitsanforderungen festzulegen und umzusetzen." + }, + { + "id": "A.5.16-1", + "ref": "A.5.16", + "kind": "control", + "title": "Identitätsmanagement", + "policy": "R08", + "section": "4.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Der vollständige Lebenszyklus von Identitäten ist zu verwalten." + }, + { + "id": "A.5.17-1", + "ref": "A.5.17", + "kind": "control", + "title": "Authentisierungsinformationen", + "policy": "R08", + "section": "4.1.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Die Zuteilung und Verwaltung von Authentisierungsinformationen ist durch einen geeigneten Verwaltungsprozess zu steuern." + }, + { + "id": "A.5.18-1", + "ref": "A.5.18", + "kind": "control", + "title": "Zugriffsrechte", + "policy": "R08", + "section": "4.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Zugriffsrechte sind gemäß der Zugriffssteuerungsrichtlinie zuzuteilen, zu überprüfen, zu ändern und zu entziehen." + }, + { + "id": "A.5.19-1", + "ref": "A.5.19", + "kind": "control", + "title": "Informationssicherheit in Lieferantenbeziehungen", + "policy": "R13", + "section": "6.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-10" + ], + "requirement": "Prozesse zur Steuerung der Informationssicherheitsrisiken aus Lieferantenbeziehungen sind festzulegen und umzusetzen." + }, + { + "id": "A.5.20-1", + "ref": "A.5.20", + "kind": "control", + "title": "Informationssicherheit in Lieferantenvereinbarungen", + "policy": "R13", + "section": "6.1.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-10" + ], + "requirement": "Relevante Informationssicherheitsanforderungen sind mit jedem Lieferanten zu vereinbaren und vertraglich festzuhalten." + }, + { + "id": "A.5.21-1", + "ref": "A.5.21", + "kind": "control", + "title": "Informationssicherheit in der IKT-Lieferkette", + "policy": "R13", + "section": "6.1.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-10" + ], + "requirement": "Prozesse zum Umgang mit Informationssicherheitsrisiken in der IKT-Produkt- und Dienstleistungs-Lieferkette sind festzulegen und umzusetzen." + }, + { + "id": "A.5.22-1", + "ref": "A.5.22", + "kind": "control", + "title": "Überwachung und Änderung von Lieferantenleistungen", + "policy": "R13", + "section": "6.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-10" + ], + "requirement": "Die Informationssicherheit von Lieferantenleistungen ist regelmäßig zu überwachen, zu überprüfen und Änderungen sind zu steuern." + }, + { + "id": "A.5.23-1", + "ref": "A.5.23", + "kind": "control", + "title": "Informationssicherheit bei Cloud-Diensten", + "policy": "R12", + "section": "5.3.4", + "new_section": false, + "condition": "FLAG_CLOUD_USED", + "soa_relevant": true, + "verfahren": [ + "VA-11" + ], + "requirement": "Prozesse für Beschaffung, Nutzung, Verwaltung und Beendigung von Cloud-Diensten sind entsprechend den Informationssicherheitsanforderungen festzulegen." + }, + { + "id": "A.5.24-1", + "ref": "A.5.24", + "kind": "control", + "title": "Incident-Management: Planung und Vorbereitung", + "policy": "R04", + "section": "1.6.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-01" + ], + "requirement": "Das Management von Informationssicherheitsvorfällen ist zu planen und vorzubereiten (Rollen, Prozesse, Verantwortlichkeiten)." + }, + { + "id": "A.5.25-1", + "ref": "A.5.25", + "kind": "control", + "title": "Bewertung und Entscheidung zu Ereignissen", + "policy": "R04", + "section": "1.6.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-01" + ], + "requirement": "Informationssicherheitsereignisse sind zu bewerten und es ist zu entscheiden, ob sie als Informationssicherheitsvorfälle einzustufen sind." + }, + { + "id": "A.5.26-1", + "ref": "A.5.26", + "kind": "control", + "title": "Reaktion auf Informationssicherheitsvorfälle", + "policy": "R04", + "section": "1.6.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-01" + ], + "requirement": "Auf Informationssicherheitsvorfälle ist gemäß dokumentierten Verfahren zu reagieren." + }, + { + "id": "A.5.27-1", + "ref": "A.5.27", + "kind": "control", + "title": "Lernen aus Informationssicherheitsvorfällen", + "policy": "R04", + "section": "1.6.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-01" + ], + "requirement": "Aus Informationssicherheitsvorfällen gewonnene Erkenntnisse sind zur Stärkung der Maßnahmen zu nutzen." + }, + { + "id": "A.5.28-1", + "ref": "A.5.28", + "kind": "control", + "title": "Sammeln von Beweismaterial", + "policy": "R04", + "section": "1.6.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-01" + ], + "requirement": "Verfahren zur Identifizierung, Sammlung, Beschaffung und Aufbewahrung von Beweismaterial zu Vorfällen sind festzulegen und umzusetzen." + }, + { + "id": "A.5.29-1", + "ref": "A.5.29", + "kind": "control", + "title": "Informationssicherheit während einer Störung", + "policy": "R04", + "section": "1.6.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-02" + ], + "requirement": "Die Aufrechterhaltung der Informationssicherheit während Störungen ist zu planen und umzusetzen." + }, + { + "id": "A.5.30-1", + "ref": "A.5.30", + "kind": "control", + "title": "IKT-Bereitschaft für Business Continuity", + "policy": "R04", + "section": "5.2.8", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-02" + ], + "requirement": "Die IKT-Bereitschaft ist auf Basis der Business-Continuity-Ziele und -Anforderungen zu planen, umzusetzen und zu testen." + }, + { + "id": "A.5.31-1", + "ref": "A.5.31", + "kind": "control", + "title": "Rechtliche und vertragliche Anforderungen", + "policy": "R14", + "section": "7.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-18" + ], + "requirement": "Rechtliche, gesetzliche, regulatorische und vertragliche Anforderungen an die Informationssicherheit sind zu identifizieren, zu dokumentieren und aktuell zu halten." + }, + { + "id": "A.5.32-1", + "ref": "A.5.32", + "kind": "control", + "title": "Geistige Eigentumsrechte", + "policy": "R14", + "section": "7.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-18" + ], + "requirement": "Geeignete Verfahren zum Schutz geistiger Eigentumsrechte sind umzusetzen." + }, + { + "id": "A.5.33-1", + "ref": "A.5.33", + "kind": "control", + "title": "Schutz von Aufzeichnungen", + "policy": "R14", + "section": "7.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-18" + ], + "requirement": "Aufzeichnungen sind vor Verlust, Zerstörung, Fälschung sowie unbefugtem Zugriff und unbefugter Veröffentlichung zu schützen." + }, + { + "id": "A.5.34-1", + "ref": "A.5.34", + "kind": "control", + "title": "Datenschutz und Schutz von PII", + "policy": "R14", + "section": "7.1.2", + "new_section": false, + "condition": "FLAG_PERSONAL_DATA", + "soa_relevant": true, + "verfahren": [ + "VA-18" + ], + "requirement": "Anforderungen an den Schutz personenbezogener Daten (PII) sind zu identifizieren und gemäß geltenden Vorgaben zu erfüllen." + }, + { + "id": "A.5.35-1", + "ref": "A.5.35", + "kind": "control", + "title": "Unabhängige Überprüfung der Informationssicherheit", + "policy": "R03", + "section": "1.5.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-15" + ], + "requirement": "Der Ansatz der Organisation zur Steuerung der Informationssicherheit ist unabhängig und in geplanten Abständen zu überprüfen." + }, + { + "id": "A.5.36-1", + "ref": "A.5.36", + "kind": "control", + "title": "Einhaltung von Richtlinien und Standards", + "policy": "R03", + "section": "1.5.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-15" + ], + "requirement": "Die Einhaltung der Informationssicherheitspolitik, themenspezifischer Richtlinien, Regeln und Standards ist regelmäßig zu überprüfen." + }, + { + "id": "A.5.37-1", + "ref": "A.5.37", + "kind": "control", + "title": "Dokumentierte Betriebsabläufe", + "policy": "R10", + "section": "ISO-BETRIEBSABLAEUFE", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Betriebsabläufe für informationsverarbeitende Einrichtungen sind zu dokumentieren und den betroffenen Personen bereitzustellen." + }, + { + "id": "A.6.1-1", + "ref": "A.6.1", + "kind": "control", + "title": "Überprüfung (Screening)", + "policy": "R05", + "section": "2.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-14" + ], + "requirement": "Hintergrundüberprüfungen von Bewerbern sind angemessen zu den Geschäftsanforderungen und gesetzeskonform durchzuführen." + }, + { + "id": "A.6.2-1", + "ref": "A.6.2", + "kind": "control", + "title": "Arbeitsvertragliche Regelungen", + "policy": "R05", + "section": "2.1.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-14" + ], + "requirement": "Die arbeitsvertraglichen Vereinbarungen legen die Verantwortlichkeiten für die Informationssicherheit fest." + }, + { + "id": "A.6.3-1", + "ref": "A.6.3", + "kind": "control", + "title": "Awareness, Ausbildung und Schulung", + "policy": "R05", + "section": "2.1.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-12" + ], + "requirement": "Beschäftigte erhalten angemessene Awareness, Aus- und Weiterbildung sowie regelmäßige Aktualisierungen der relevanten Richtlinien." + }, + { + "id": "A.6.4-1", + "ref": "A.6.4", + "kind": "control", + "title": "Disziplinarverfahren", + "policy": "R05", + "section": "ISO-DISZIPLIN", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Ein Disziplinarverfahren für Verstöße gegen die Informationssicherheit ist festzulegen und zu kommunizieren." + }, + { + "id": "A.6.5-1", + "ref": "A.6.5", + "kind": "control", + "title": "Verantwortlichkeiten nach Beendigung oder Wechsel", + "policy": "R05", + "section": "2.1.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-14" + ], + "requirement": "Fortbestehende Informationssicherheitsverantwortlichkeiten nach Beendigung oder Wechsel des Beschäftigungsverhältnisses sind zu definieren und durchzusetzen." + }, + { + "id": "A.6.6-1", + "ref": "A.6.6", + "kind": "control", + "title": "Vertraulichkeitsvereinbarungen", + "policy": "R05", + "section": "2.1.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-14" + ], + "requirement": "Vertraulichkeits- bzw. Geheimhaltungsvereinbarungen sind zu identifizieren, zu dokumentieren und regelmäßig zu überprüfen." + }, + { + "id": "A.6.7-1", + "ref": "A.6.7", + "kind": "control", + "title": "Remote-Arbeit", + "policy": "R06", + "section": "2.1.4", + "new_section": false, + "condition": "FLAG_MOBILE_WORK", + "soa_relevant": true, + "verfahren": [], + "requirement": "Sicherheitsmaßnahmen für das Arbeiten außerhalb der Räumlichkeiten der Organisation sind umzusetzen." + }, + { + "id": "A.6.8-1", + "ref": "A.6.8", + "kind": "control", + "title": "Meldung von Informationssicherheitsereignissen", + "policy": "R04", + "section": "1.6.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-01" + ], + "requirement": "Ein Mechanismus zur zeitnahen Meldung beobachteter oder vermuteter Informationssicherheitsereignisse ist bereitzustellen." + }, + { + "id": "A.7.1-1", + "ref": "A.7.1", + "kind": "control", + "title": "Physische Sicherheitsperimeter", + "policy": "R07", + "section": "3.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Sicherheitsperimeter sind zu definieren und zum Schutz von Bereichen mit Informationen und Assets zu nutzen." + }, + { + "id": "A.7.2-1", + "ref": "A.7.2", + "kind": "control", + "title": "Physische Zutrittssteuerung", + "policy": "R07", + "section": "3.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Sichere Zutrittskontrollen und Zutrittspunkte sind einzurichten, um den Zugang auf Berechtigte zu beschränken." + }, + { + "id": "A.7.3-1", + "ref": "A.7.3", + "kind": "control", + "title": "Sicherung von Büros, Räumen und Einrichtungen", + "policy": "R07", + "section": "3.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Physische Sicherheit für Büros, Räume und Einrichtungen ist zu gestalten und umzusetzen." + }, + { + "id": "A.7.4-1", + "ref": "A.7.4", + "kind": "control", + "title": "Physische Überwachung", + "policy": "R07", + "section": "3.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Räumlichkeiten sind kontinuierlich auf unbefugten physischen Zugang zu überwachen." + }, + { + "id": "A.7.5-1", + "ref": "A.7.5", + "kind": "control", + "title": "Schutz vor physischen und umweltbedingten Bedrohungen", + "policy": "R07", + "section": "ISO-PHY-UMWELT", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Schutz gegen physische und umweltbedingte Bedrohungen ist zu gestalten und umzusetzen." + }, + { + "id": "A.7.6-1", + "ref": "A.7.6", + "kind": "control", + "title": "Arbeiten in Sicherheitsbereichen", + "policy": "R07", + "section": "3.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Für das Arbeiten in Sicherheitsbereichen sind Maßnahmen festzulegen und umzusetzen." + }, + { + "id": "A.7.7-1", + "ref": "A.7.7", + "kind": "control", + "title": "Aufgeräumter Arbeitsplatz und Bildschirm", + "policy": "R07", + "section": "ISO-PHY-CLEARDESK", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Regeln für einen aufgeräumten Arbeitsplatz und gesperrte Bildschirme sind festzulegen und umzusetzen." + }, + { + "id": "A.7.8-1", + "ref": "A.7.8", + "kind": "control", + "title": "Platzierung und Schutz von Betriebsmitteln", + "policy": "R07", + "section": "ISO-PHY-UMWELT", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Betriebsmittel sind sicher zu platzieren und zu schützen." + }, + { + "id": "A.7.9-1", + "ref": "A.7.9", + "kind": "control", + "title": "Sicherheit von Assets außerhalb des Geländes", + "policy": "R06", + "section": "3.1.4", + "new_section": false, + "condition": "FLAG_MOBILE_DEVICES", + "soa_relevant": true, + "verfahren": [], + "requirement": "Assets, die außerhalb der Räumlichkeiten genutzt werden, sind zu schützen." + }, + { + "id": "A.7.10-1", + "ref": "A.7.10", + "kind": "control", + "title": "Speichermedien", + "policy": "R06", + "section": "3.1.4", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Speichermedien sind über ihren gesamten Lebenszyklus (Erwerb, Nutzung, Transport, Entsorgung) entsprechend dem Klassifizierungsschema zu schützen." + }, + { + "id": "A.7.11-1", + "ref": "A.7.11", + "kind": "control", + "title": "Versorgungseinrichtungen", + "policy": "R07", + "section": "ISO-PHY-UMWELT", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Einrichtungen sind vor Ausfällen und Störungen der Versorgung (z. B. Strom, Klima) zu schützen." + }, + { + "id": "A.7.12-1", + "ref": "A.7.12", + "kind": "control", + "title": "Verkabelungssicherheit", + "policy": "R07", + "section": "ISO-PHY-UMWELT", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-17" + ], + "requirement": "Verkabelung für Strom und Daten ist vor Abhören, Störung und Beschädigung zu schützen." + }, + { + "id": "A.7.13-1", + "ref": "A.7.13", + "kind": "control", + "title": "Wartung von Betriebsmitteln", + "policy": "R07", + "section": "ISO-PHY-UMWELT", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-04" + ], + "requirement": "Betriebsmittel sind ordnungsgemäß zu warten, um Verfügbarkeit und Integrität sicherzustellen." + }, + { + "id": "A.7.14-1", + "ref": "A.7.14", + "kind": "control", + "title": "Sichere Entsorgung oder Wiederverwendung", + "policy": "R11", + "section": "5.3.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "Betriebsmittel mit Speichermedien sind vor Entsorgung oder Wiederverwendung sicher zu bereinigen (Datenlöschung)." + }, + { + "id": "A.8.1-1", + "ref": "A.8.1", + "kind": "control", + "title": "Endgeräte der Benutzer", + "policy": "R06", + "section": "3.1.4", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Informationen, die auf Endgeräten der Benutzer gespeichert, verarbeitet oder darüber zugänglich sind, sind zu schützen." + }, + { + "id": "A.8.2-1", + "ref": "A.8.2", + "kind": "control", + "title": "Privilegierte Zugriffsrechte", + "policy": "R08", + "section": "4.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Die Zuteilung und Nutzung privilegierter Zugriffsrechte ist einzuschränken und eng zu steuern." + }, + { + "id": "A.8.3-1", + "ref": "A.8.3", + "kind": "control", + "title": "Einschränkung des Informationszugriffs", + "policy": "R08", + "section": "4.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Der Zugriff auf Informationen und Anwendungsfunktionen ist gemäß der Zugriffssteuerungsrichtlinie einzuschränken." + }, + { + "id": "A.8.4-1", + "ref": "A.8.4", + "kind": "control", + "title": "Zugriff auf Quellcode", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Der Lese- und Schreibzugriff auf Quellcode, Entwicklungswerkzeuge und Softwarebibliotheken ist angemessen zu steuern." + }, + { + "id": "A.8.5-1", + "ref": "A.8.5", + "kind": "control", + "title": "Sichere Authentisierung", + "policy": "R08", + "section": "4.1.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Sichere Authentisierungstechnologien und -verfahren sind auf Basis der Zugriffsbeschränkungen und der Zugriffssteuerungsrichtlinie einzusetzen." + }, + { + "id": "A.8.6-1", + "ref": "A.8.6", + "kind": "control", + "title": "Kapazitätssteuerung", + "policy": "R10", + "section": "ISO-KAPAZITAET", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Ressourcen sind zu überwachen und die Kapazität ist an den aktuellen und erwarteten Bedarf anzupassen." + }, + { + "id": "A.8.7-1", + "ref": "A.8.7", + "kind": "control", + "title": "Schutz vor Malware", + "policy": "R10", + "section": "5.2.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Schutz vor Schadsoftware ist umzusetzen und durch angemessene Awareness der Benutzer zu unterstützen." + }, + { + "id": "A.8.8-1", + "ref": "A.8.8", + "kind": "control", + "title": "Management technischer Schwachstellen", + "policy": "R10", + "section": "5.2.5", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-06" + ], + "requirement": "Informationen über technische Schwachstellen sind zu beschaffen, die Betroffenheit zu bewerten und geeignete Maßnahmen zu ergreifen." + }, + { + "id": "A.8.9-1", + "ref": "A.8.9", + "kind": "control", + "title": "Konfigurationsmanagement", + "policy": "R10", + "section": "5.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-04" + ], + "requirement": "Konfigurationen von Hardware, Software, Diensten und Netzen sind festzulegen, zu dokumentieren, umzusetzen, zu überwachen und zu überprüfen." + }, + { + "id": "A.8.10-1", + "ref": "A.8.10", + "kind": "control", + "title": "Löschung von Informationen", + "policy": "R11", + "section": "5.3.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-08" + ], + "requirement": "In Systemen und auf Medien gespeicherte Informationen sind zu löschen, sobald sie nicht mehr benötigt werden." + }, + { + "id": "A.8.11-1", + "ref": "A.8.11", + "kind": "control", + "title": "Datenmaskierung", + "policy": "R02", + "section": "ISO-MASKIERUNG", + "new_section": true, + "condition": "FLAG_PERSONAL_DATA", + "soa_relevant": true, + "verfahren": [], + "requirement": "Datenmaskierung ist gemäß den Zugriffs- und Datenschutzanforderungen einzusetzen." + }, + { + "id": "A.8.12-1", + "ref": "A.8.12", + "kind": "control", + "title": "Verhinderung von Datenlecks", + "policy": "R10", + "section": "ISO-DLP", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Maßnahmen zur Verhinderung von Datenlecks sind auf Systeme, Netze und Geräte anzuwenden, die sensible Informationen verarbeiten." + }, + { + "id": "A.8.13-1", + "ref": "A.8.13", + "kind": "control", + "title": "Informationssicherung (Backup)", + "policy": "R10", + "section": "5.2.9", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-05" + ], + "requirement": "Sicherungskopien von Informationen, Software und Systemen sind gemäß Sicherungskonzept zu erstellen und regelmäßig zu testen." + }, + { + "id": "A.8.14-1", + "ref": "A.8.14", + "kind": "control", + "title": "Redundanz der Verarbeitungseinrichtungen", + "policy": "R04", + "section": "5.2.8", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-02" + ], + "requirement": "Informationsverarbeitende Einrichtungen sind mit ausreichender Redundanz auszulegen, um die Verfügbarkeitsanforderungen zu erfüllen." + }, + { + "id": "A.8.15-1", + "ref": "A.8.15", + "kind": "control", + "title": "Protokollierung (Logging)", + "policy": "R10", + "section": "5.2.4", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-13" + ], + "requirement": "Protokolle über Aktivitäten, Ausnahmen, Fehler und Ereignisse sind zu erzeugen, zu speichern, zu schützen und auszuwerten." + }, + { + "id": "A.8.16-1", + "ref": "A.8.16", + "kind": "control", + "title": "Überwachungsaktivitäten", + "policy": "R10", + "section": "5.2.4", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-13" + ], + "requirement": "Netze, Systeme und Anwendungen sind auf anomales Verhalten zu überwachen und mögliche Vorfälle zu bewerten." + }, + { + "id": "A.8.17-1", + "ref": "A.8.17", + "kind": "control", + "title": "Uhrzeitsynchronisation", + "policy": "R10", + "section": "ISO-ZEITSYNC", + "new_section": true, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-13" + ], + "requirement": "Die Uhren der Systeme sind auf zugelassene Zeitquellen zu synchronisieren." + }, + { + "id": "A.8.18-1", + "ref": "A.8.18", + "kind": "control", + "title": "Nutzung privilegierter Hilfsprogramme", + "policy": "R08", + "section": "4.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-03" + ], + "requirement": "Die Nutzung von Hilfsprogrammen, die System- und Anwendungskontrollen umgehen können, ist einzuschränken und streng zu steuern." + }, + { + "id": "A.8.19-1", + "ref": "A.8.19", + "kind": "control", + "title": "Softwareinstallation auf Produktivsystemen", + "policy": "R02", + "section": "1.3.4", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-04" + ], + "requirement": "Verfahren und Maßnahmen zur sicheren Verwaltung der Softwareinstallation auf Produktivsystemen sind umzusetzen." + }, + { + "id": "A.8.20-1", + "ref": "A.8.20", + "kind": "control", + "title": "Netzwerksicherheit", + "policy": "R10", + "section": "5.2.7", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Netze und Netzwerkgeräte sind zu sichern, zu verwalten und zu steuern, um Informationen zu schützen." + }, + { + "id": "A.8.21-1", + "ref": "A.8.21", + "kind": "control", + "title": "Sicherheit von Netzwerkdiensten", + "policy": "R11", + "section": "5.3.2", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Sicherheitsmechanismen, Dienstgüten und Anforderungen an Netzwerkdienste sind zu identifizieren, umzusetzen und zu überwachen." + }, + { + "id": "A.8.22-1", + "ref": "A.8.22", + "kind": "control", + "title": "Netzwerksegmentierung", + "policy": "R10", + "section": "5.2.7", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Gruppen von Informationsdiensten, Nutzern und Systemen sind in Netzen zu segmentieren." + }, + { + "id": "A.8.23-1", + "ref": "A.8.23", + "kind": "control", + "title": "Web-Filterung", + "policy": "R10", + "section": "5.2.3", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [], + "requirement": "Der Zugriff auf externe Webseiten ist zu steuern, um die Exposition gegenüber schädlichen Inhalten zu reduzieren." + }, + { + "id": "A.8.24-1", + "ref": "A.8.24", + "kind": "control", + "title": "Nutzung von Kryptographie", + "policy": "R09", + "section": "5.1.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-07" + ], + "requirement": "Regeln für die wirksame Nutzung von Kryptographie einschließlich Schlüsselverwaltung sind festzulegen und umzusetzen." + }, + { + "id": "A.8.25-1", + "ref": "A.8.25", + "kind": "control", + "title": "Sicherer Entwicklungslebenszyklus", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Regeln für einen sicheren Entwicklungslebenszyklus von Software und Systemen sind festzulegen und anzuwenden." + }, + { + "id": "A.8.26-1", + "ref": "A.8.26", + "kind": "control", + "title": "Sicherheitsanforderungen an Anwendungen", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Informationssicherheitsanforderungen sind bei Entwicklung oder Beschaffung von Anwendungen zu ermitteln, zu spezifizieren und zu berücksichtigen." + }, + { + "id": "A.8.27-1", + "ref": "A.8.27", + "kind": "control", + "title": "Sichere Systemarchitektur und -prinzipien", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Grundsätze für die Entwicklung sicherer Systeme sind festzulegen, zu dokumentieren und anzuwenden." + }, + { + "id": "A.8.28-1", + "ref": "A.8.28", + "kind": "control", + "title": "Sichere Programmierung", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Grundsätze für sichere Programmierung sind auf die Softwareentwicklung anzuwenden." + }, + { + "id": "A.8.29-1", + "ref": "A.8.29", + "kind": "control", + "title": "Sicherheitstests in Entwicklung und Abnahme", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Sicherheitstests sind in den Entwicklungs- und Abnahmeprozess zu integrieren." + }, + { + "id": "A.8.30-1", + "ref": "A.8.30", + "kind": "control", + "title": "Ausgelagerte Entwicklung", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Ausgelagerte Systementwicklung ist zu steuern, zu überwachen und zu überprüfen." + }, + { + "id": "A.8.31-1", + "ref": "A.8.31", + "kind": "control", + "title": "Trennung von Entwicklungs-, Test- und Produktionsumgebungen", + "policy": "R10", + "section": "5.2.2", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Entwicklungs-, Test- und Produktionsumgebungen sind zu trennen und zu schützen." + }, + { + "id": "A.8.32-1", + "ref": "A.8.32", + "kind": "control", + "title": "Änderungsmanagement", + "policy": "R10", + "section": "5.2.1", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-04" + ], + "requirement": "Änderungen an informationsverarbeitenden Einrichtungen und Systemen sind einem Änderungsmanagement zu unterziehen." + }, + { + "id": "A.8.33-1", + "ref": "A.8.33", + "kind": "control", + "title": "Testinformationen", + "policy": "R11", + "section": "5.3.1", + "new_section": false, + "condition": "FLAG_DEV_INHOUSE", + "soa_relevant": true, + "verfahren": [ + "VA-16" + ], + "requirement": "Testinformationen sind sorgfältig auszuwählen, zu schützen und zu verwalten." + }, + { + "id": "A.8.34-1", + "ref": "A.8.34", + "kind": "control", + "title": "Schutz von Systemen bei Audit-Tests", + "policy": "R10", + "section": "5.2.6", + "new_section": false, + "condition": null, + "soa_relevant": true, + "verfahren": [ + "VA-15" + ], + "requirement": "Audit-Tests und ähnliche Prüftätigkeiten an Produktivsystemen sind zu planen und zu vereinbaren, um Beeinträchtigungen zu vermeiden." + } + ] +} \ No newline at end of file diff --git a/seed/isms-vorlagenpaket-v2/_iso_sections.json b/seed/isms-vorlagenpaket-v2/_iso_sections.json new file mode 100644 index 0000000..d01a741 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_iso_sections.json @@ -0,0 +1,81 @@ +{ + "hinweis": "Redaktionell pflegbare Texte der ISO-only-Abschnitte. Individualisierung ausschließlich über {{VARIABLEN}} und Baseline-IDs (BL-*) — keine Klartextwerte eintragen.", + "abschnitte": { + "ISO-LEITLINIE": { + "titel": "Informationssicherheitspolitik, Ziele und Kommunikation", + "umsetzung": "Diese Leitlinie wird von der {{ROLE_MANAGEMENT}} freigegeben, im {{TOOL_NAME}} veröffentlicht und allen Beschäftigten sowie relevanten Dritten bekannt gemacht; die Kenntnisnahme wird je Fassung dokumentiert. Die Überprüfung erfolgt mindestens {{POLICY_REVIEW_CYCLE}} sowie bei wesentlichen Änderungen (BL-GOV-03). Die themenspezifischen Richtlinien und die Verfahrensanweisungen konkretisieren sie und durchlaufen denselben Freigabe- und Prüfzyklus. Die Informationssicherheitsziele sind messbar formuliert und mit Zielwert, verantwortlicher Rolle und Termin im {{TOOL_NAME}} hinterlegt; ihre Erreichung wird {{MGMT_REVIEW_CYCLE}} bewertet. Für die interne und externe Kommunikation zur Informationssicherheit ist festgelegt, worüber, wann, mit wem und durch wen kommuniziert wird; zentraler Ansprechpartner ist {{ROLE_ISB}}." + }, + "ISO-MS-KONTEXT": { + "titel": "Kontext, interessierte Parteien und Anwendungsbereich des ISMS", + "umsetzung": "Interne und externe Themen sowie die relevanten interessierten Parteien und deren Anforderungen werden im {{TOOL_NAME}} als Kontext- und Stakeholderanalyse geführt und mindestens {{POLICY_REVIEW_CYCLE}} sowie bei wesentlichen Änderungen aktualisiert. Der Anwendungsbereich des ISMS ({{ISMS_SCOPE}}) ist als dokumentierte Information festgelegt und benennt Standorte, Prozesse, Organisationseinheiten und IT-Dienste sowie Schnittstellen und Abhängigkeiten zu Dritten; Ausschlüsse werden begründet. Das ISMS wird nach dem PDCA-Zyklus betrieben und fortlaufend verbessert. Verantwortlich: {{ROLE_ISB}}; Freigabe: {{ROLE_MANAGEMENT}}." + }, + "ISO-MS-CHANGE": { + "titel": "Planung von Änderungen am ISMS", + "umsetzung": "Änderungen am ISMS — Anwendungsbereich, Organisation, Rollen, wesentliche Prozesse oder Systeme — werden geplant, vor der Umsetzung bewertet und im {{TOOL_NAME}} dokumentiert. Die Bewertung umfasst Zweck und mögliche Folgen der Änderung, Auswirkungen auf Risiken und Maßnahmen, benötigte Ressourcen sowie die Zuweisung von Verantwortlichkeiten. Die Freigabe erfolgt durch {{ROLE_MANAGEMENT}}; technische Änderungen laufen zusätzlich über das Änderungsmanagement (BL-OPS-09, siehe {{LINK:VA-04}})." + }, + "ISO-MS-DOKU": { + "titel": "Lenkung dokumentierter Information", + "umsetzung": "Die dokumentierte Information des ISMS wird im {{TOOL_NAME}} geführt. Jedes Dokument trägt Titel, eindeutige Kennung, Version, Datum, Status, verantwortliche Rolle und Freigebenden; Erstellung und Änderung durchlaufen Prüfung und Freigabe im Vier-Augen-Prinzip (BL-GOV-03). Die Lenkung stellt Verfügbarkeit für die berechtigten Rollen, Schutz vor unbefugter Änderung, gesteuerte Verteilung, Versionsführung mit Änderungsverlauf und die Aufbewahrung abgelöster Fassungen ({{RECORDS_RETENTION}}) sicher. Dokumente externer Herkunft werden gekennzeichnet und ebenso gelenkt. Der Prüfzyklus beträgt {{POLICY_REVIEW_CYCLE}}." + }, + "ISO-KONTAKTE": { + "titel": "Kontakte zu Behörden und Interessengruppen", + "umsetzung": "{{ROLE_ISB}} pflegt eine Kontaktliste der relevanten Behörden und Meldestellen ({{AUTHORITY_CONTACTS}}) mit Zuständigkeit, Erreichbarkeit und Meldeweg; sie wird {{POLICY_REVIEW_CYCLE}} auf Aktualität geprüft und ist im Notfall auch ohne IT-Zugriff verfügbar. Meldepflichten und Fristen sind im Incident-Verfahren hinterlegt ({{LINK:VA-01}}). Zusätzlich werden fachliche Kontakte zu Interessengruppen, Fachforen und Sicherheitsverbänden gepflegt; die daraus gewonnenen Erkenntnisse fließen in die Bewertung von Bedrohungsinformationen ein." + }, + "ISO-SOA": { + "titel": "Erklärung zur Anwendbarkeit (SoA)", + "umsetzung": "Aus der Risikobehandlung wird bestimmt, welche Maßnahmen erforderlich sind; das Ergebnis wird mit Anhang A abgeglichen, um übersehene Maßnahmen zu erkennen. Die Erklärung zur Anwendbarkeit wird im {{TOOL_NAME}} geführt und enthält je Control: Anwendbarkeit, Begründung der Einbeziehung, Herkunft (Risiko-ID, gesetzliche oder vertragliche Anforderung), Umsetzungsstatus, verantwortliche Rolle, Verweis auf Richtlinie und Verfahren sowie Nachweis; bei Ausschluss wird die Begründung dokumentiert. Der Risikobehandlungsplan und die Akzeptanz der verbleibenden Risiken werden von den jeweiligen Risikoeigentümern genehmigt; die SoA wird von {{ROLE_MANAGEMENT}} freigegeben und bei jeder Risikobeurteilung ({{RISK_REVIEW_CYCLE}}) aktualisiert." + }, + "ISO-MS-BETRIEB": { + "titel": "Betriebliche Planung und Steuerung", + "umsetzung": "Die zur Erfüllung der Informationssicherheitsanforderungen erforderlichen Prozesse sind in den Verfahrensanweisungen festgelegt und werden im {{TOOL_NAME}} gesteuert; je Prozess sind Auslöser, verantwortliche Rolle, Fristen und Nachweise bestimmt. Geplante Änderungen werden gesteuert und ihre Folgen bewertet; unbeabsichtigte Änderungen werden überprüft und erforderlichenfalls korrigiert. Ausgelagerte Prozesse werden über die Lieferantensteuerung ({{LINK:R13}}) bestimmt und überwacht. Nachweise über die planmäßige Durchführung werden im Nachweisregister ({{LINK:NACHWEISREGISTER}}) geführt." + }, + "ISO-MS-MESSUNG": { + "titel": "Überwachung, Messung, Analyse und Bewertung", + "umsetzung": "Für die Bewertung der Informationssicherheitsleistung und der Wirksamkeit des ISMS ist festgelegt, was gemessen wird (Kennzahlenblatt im {{TOOL_NAME}}), mit welcher Methode und Datenquelle, in welchem Takt gemessen wird, wer misst, wann die Ergebnisse ausgewertet werden und wer sie auswertet. Die Kennzahlen decken mindestens Vorfallbearbeitung, Schwachstellen- und Patchbehebung, Rezertifizierung von Berechtigungen, Wiederherstellungstests, Awareness-Teilnahme und offene Maßnahmen ab; je Kennzahl sind Zielwert und verantwortliche Rolle hinterlegt. Ergebnisse und Trends gehen {{MGMT_REVIEW_CYCLE}} in die Managementbewertung ein; eine Abweichung vom Zielwert löst eine Maßnahme aus." + }, + "ISO-MS-MGMTREVIEW": { + "titel": "Managementbewertung", + "umsetzung": "{{ROLE_MANAGEMENT}} bewertet das ISMS mindestens {{MGMT_REVIEW_CYCLE}} anhand einer festen Tagesordnung (BL-GOV-02). Eingaben sind mindestens: Status der Maßnahmen aus früheren Bewertungen; Änderungen relevanter interner und externer Themen sowie der Anforderungen interessierter Parteien; Rückmeldungen zur Informationssicherheitsleistung (Nichtkonformitäten und Korrekturmaßnahmen, Überwachungs- und Messergebnisse, Auditergebnisse, Erreichung der Informationssicherheitsziele); Rückmeldungen interessierter Parteien; Ergebnisse der Risikobeurteilung und Status des Risikobehandlungsplans; Verbesserungsmöglichkeiten. Ergebnisse sind Entscheidungen zu Verbesserungsmöglichkeiten und zu Änderungsbedarf am ISMS, jeweils mit verantwortlicher Rolle und Termin. Das Protokoll wird im {{TOOL_NAME}} aufbewahrt." + }, + "ISO-MS-CAPA": { + "titel": "Nichtkonformität, Korrekturmaßnahmen und fortlaufende Verbesserung", + "umsetzung": "Nichtkonformitäten aus Audits, Kontrollen, Vorfällen, Kennzahlenabweichungen und Hinweisen werden im {{TOOL_NAME}} erfasst. Je Fall werden die Sofortkorrektur und der Umgang mit den Folgen festgelegt, die Ursache analysiert und bewertet, ob gleichartige Nichtkonformitäten anderswo bestehen oder auftreten können. Erforderliche Korrekturmaßnahmen werden mit verantwortlicher Rolle und Termin umgesetzt; ihre Wirksamkeit wird nach Ablauf des festgelegten Wirksamkeitsintervalls bewertet und erforderlichenfalls werden Risiken, Maßnahmen und Dokumente angepasst. Art der Nichtkonformität, ergriffene Maßnahmen und Ergebnis der Wirksamkeitsbewertung werden aufbewahrt. Eignung, Angemessenheit und Wirksamkeit des ISMS werden fortlaufend verbessert; der Nachweis erfolgt über Kennzahlen und Managementbewertung." + }, + "ISO-THREATINTEL": { + "titel": "Bedrohungsinformationen", + "umsetzung": "Informationen über Bedrohungen werden regelmäßig aus benannten Quellen ({{THREAT_INTEL_SOURCES}}) bezogen und von {{ROLE_IT_LEAD}} auf Relevanz für die eigenen Systeme und Dienste bewertet. Relevante Erkenntnisse führen zu Maßnahmen im Schwachstellen- und Patchmanagement ({{LINK:VA-06}}), zu Anpassungen der Überwachung ({{LINK:VA-13}}) oder zu einer erneuten Risikobeurteilung. Bewertung und abgeleitete Maßnahmen werden im {{TOOL_TICKET}} dokumentiert." + }, + "ISO-BETRIEBSABLAEUFE": { + "titel": "Dokumentierte Betriebsabläufe", + "umsetzung": "Betriebsabläufe für informationsverarbeitende Einrichtungen sind dokumentiert und den ausführenden Personen zugänglich. Abgedeckt sind Inbetriebnahme und Konfiguration, Betrieb und Überwachung, Datensicherung, Behandlung von Störungen, Wartung sowie Außerbetriebnahme. Die Dokumentation wird bei Änderungen über das Änderungsmanagement (BL-OPS-09) aktualisiert und mindestens {{POLICY_REVIEW_CYCLE}} auf Aktualität geprüft. Verantwortlich: {{ROLE_IT_LEAD}}." + }, + "ISO-KAPAZITAET": { + "titel": "Kapazitätssteuerung", + "umsetzung": "Die Auslastung der maßgeblichen Ressourcen — Rechenleistung, Arbeitsspeicher, Speicherplatz, Netzbandbreite, Lizenzen sowie personelle Kapazität im IT-Betrieb — wird {{CAPACITY_REVIEW_FREQ}} überwacht (BL-OPS-11). Überschrittene Schwellenwerte lösen eine Meldung aus; der künftige Bedarf wird bei Projekten und wesentlichen Änderungen berücksichtigt. Kapazitätsengpässe mit Auswirkung auf die Verfügbarkeitsanforderungen werden als Risiko erfasst und behandelt." + }, + "ISO-DLP": { + "titel": "Verhinderung von Datenabfluss", + "umsetzung": "Für Systeme, Netze und Geräte, die schutzbedürftige Informationen verarbeiten, sind Maßnahmen gegen unbefugten Abfluss umgesetzt (BL-OPS-12); abgedeckt sind mindestens {{DLP_SCOPE}}. Die Maßnahmen richten sich nach der Klassifizierung ({{LINK:R02}}): Regeln zur Weitergabe, Kontrolle der Übertragungswege, Beschränkung von Wechseldatenträgern (BL-EP-03) sowie Protokollierung und Auswertung auffälliger Übertragungen (BL-OPS-04). Erkannte Verstöße werden als Sicherheitsereignis behandelt ({{LINK:VA-01}}); bei personenbezogener Auswertung werden Mitbestimmungsrechte gewahrt." + }, + "ISO-ZEITSYNC": { + "titel": "Uhrzeitsynchronisation", + "umsetzung": "Die Systemuhren aller protokollierenden Systeme werden auf {{NTP_SOURCES}} synchronisiert (BL-OPS-10). Abweichungen werden überwacht und gemeldet. Eine einheitliche Zeitbasis und Zeitzone ist Voraussetzung für die Auswertbarkeit der Protokolle ({{LINK:VA-13}}) und für die Beweissicherung bei Vorfällen." + }, + "ISO-DISZIPLIN": { + "titel": "Vorgehen bei Verstößen", + "umsetzung": "Für Verstöße gegen die Informationssicherheitsvorgaben besteht ein abgestuftes, dokumentiertes Vorgehen, das im Voraus kommuniziert ist. Es berücksichtigt Art und Schwere des Verstoßes, Vorsatz oder Fahrlässigkeit, Wiederholung sowie den Schulungsstand der betroffenen Person. Das Verfahren wird von {{ROLE_HR_LEAD}} in Abstimmung mit {{ROLE_ISB}} geführt; arbeitsrechtliche Vorgaben und Mitbestimmungsrechte werden gewahrt. Die Anwendung wird vertraulich dokumentiert." + }, + "ISO-PHY-UMWELT": { + "titel": "Umgebungsschutz, Versorgung, Verkabelung und Wartung", + "umsetzung": "Standorte und technische Einrichtungen sind gegen physische und umweltbedingte Bedrohungen geschützt (BL-PHY-03): Brandfrüherkennung, Schutz gegen Wasser und Feuchtigkeit, Temperatur- und Feuchteüberwachung in Technikräumen sowie Berücksichtigung standortspezifischer Gefahren. Betriebsmittel sind so platziert, dass Einsicht, unbefugter Zugriff und Umgebungsrisiken minimiert werden. Strom- und Klimaversorgung sind für kritische Systeme unterbrechungsfrei ausgelegt und werden regelmäßig geprüft. Strom- und Datenverkabelung ist gegen Beschädigung und unbefugten Zugriff geschützt und dokumentiert. Betriebsmittel werden nach Herstellervorgabe gewartet; Wartungen erfolgen nur durch berechtigtes Personal, werden geplant und protokolliert und bei externer Durchführung begleitet." + }, + "ISO-PHY-CLEARDESK": { + "titel": "Aufgeräumter Arbeitsplatz und Bildschirmsperre", + "umsetzung": "Es gelten verbindliche Regeln für einen aufgeräumten Arbeitsplatz und gesperrte Bildschirme (BL-PHY-04): Schutzbedürftige Unterlagen und Datenträger werden bei Abwesenheit verschlossen aufbewahrt; Bildschirme werden beim Verlassen des Arbeitsplatzes gesperrt und sperren automatisch nach {{SESSION_TIMEOUT}}. Ausdrucke werden unmittelbar entnommen, nicht mehr benötigte Unterlagen schutzbedarfsgerecht vernichtet (BL-DEL-01). Die Regeln gelten auch im Homeoffice und an mobilen Arbeitsplätzen ({{LINK:R06}}); die Einhaltung wird stichprobenartig geprüft." + }, + "ISO-MASKIERUNG": { + "titel": "Datenmaskierung und Pseudonymisierung", + "umsetzung": "Wo der volle Informationsgehalt für den Verwendungszweck nicht erforderlich ist, werden Daten maskiert, pseudonymisiert oder anonymisiert. Das gilt insbesondere für Test-, Schulungs- und Entwicklungsumgebungen ({{LINK:R11}}), für Auswertungen sowie für Anzeigen mit eingeschränktem Zugriffsbedarf. Umfang und Verfahren richten sich nach der Klassifizierung und den Datenschutzanforderungen ({{LINK:R14}}); die Zulässigkeit einer Wiederherstellung des Personenbezugs und deren Absicherung sind geregelt." + } + } +} \ No newline at end of file diff --git a/seed/isms-vorlagenpaket-v2/_iso_sections_en.json b/seed/isms-vorlagenpaket-v2/_iso_sections_en.json new file mode 100644 index 0000000..a618d9f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_iso_sections_en.json @@ -0,0 +1,81 @@ +{ + "hinweis": "English texts of the ISO-only sections. Individualisation exclusively via {{VARIABLES}} and baseline IDs (BL-*) — do not enter literal values.", + "abschnitte": { + "ISO-LEITLINIE": { + "titel": "Information security policy, objectives and communication", + "umsetzung": "This policy is approved by {{ROLE_MANAGEMENT}}, published in {{TOOL_NAME}} and made known to all staff and relevant third parties; acknowledgement is recorded per version. It is reviewed at least {{POLICY_REVIEW_CYCLE}} and upon significant change (BL-GOV-03). The thematic policies and the procedures elaborate it and follow the same approval and review cycle. The information security objectives are stated in measurable terms and held in {{TOOL_NAME}} with target value, responsible role and due date; their achievement is evaluated {{MGMT_REVIEW_CYCLE}}. For internal and external communication on information security it is defined what is communicated, when, with whom and by whom; the central point of contact is {{ROLE_ISB}}." + }, + "ISO-MS-KONTEXT": { + "titel": "Context, interested parties and scope of the ISMS", + "umsetzung": "Internal and external issues as well as the relevant interested parties and their requirements are maintained in {{TOOL_NAME}} as a context and stakeholder analysis and updated at least {{POLICY_REVIEW_CYCLE}} and upon significant change. The scope of the ISMS ({{ISMS_SCOPE}}) is documented information and names sites, processes, organisational units and IT services as well as interfaces and dependencies on third parties; exclusions are justified. The ISMS is operated according to the PDCA cycle and continually improved. Responsible: {{ROLE_ISB}}; approval: {{ROLE_MANAGEMENT}}." + }, + "ISO-MS-CHANGE": { + "titel": "Planning of changes to the ISMS", + "umsetzung": "Changes to the ISMS — scope, organisation, roles, key processes or systems — are planned, assessed before implementation and documented in {{TOOL_NAME}}. The assessment covers the purpose and potential consequences of the change, effects on risks and controls, the resources required and the assignment of responsibilities. Approval is given by {{ROLE_MANAGEMENT}}; technical changes additionally run through change management (BL-OPS-09, see {{LINK:VA-04}})." + }, + "ISO-MS-DOKU": { + "titel": "Control of documented information", + "umsetzung": "The documented information of the ISMS is maintained in {{TOOL_NAME}}. Every document carries a title, a unique identifier, version, date, status, responsible role and approver; creation and modification pass through review and four-eyes approval (BL-GOV-03). Control ensures availability to the authorised roles, protection against unauthorised modification, managed distribution, version control with a change history and retention of superseded versions ({{RECORDS_RETENTION}}). Documents of external origin are identified and controlled in the same way. Review cycle: {{POLICY_REVIEW_CYCLE}}." + }, + "ISO-KONTAKTE": { + "titel": "Contact with authorities and interest groups", + "umsetzung": "{{ROLE_ISB}} maintains a contact list of the relevant authorities and reporting bodies ({{AUTHORITY_CONTACTS}}) with responsibility, availability and reporting channel; it is checked for currency {{POLICY_REVIEW_CYCLE}} and is available in an emergency without IT access. Reporting obligations and deadlines are held in the incident procedure ({{LINK:VA-01}}). In addition, professional contacts with interest groups, forums and security associations are maintained; the resulting insights feed into the evaluation of threat intelligence." + }, + "ISO-SOA": { + "titel": "Statement of Applicability (SoA)", + "umsetzung": "The risk treatment determines which controls are necessary; the result is compared against Annex A to identify controls that may have been overlooked. The Statement of Applicability is maintained in {{TOOL_NAME}} and states for each control: applicability, justification for inclusion, origin (risk ID, legal or contractual requirement), implementation status, responsible role, reference to policy and procedure as well as evidence; where a control is excluded, the justification is documented. The risk treatment plan and the acceptance of residual risks are approved by the respective risk owners; the SoA is approved by {{ROLE_MANAGEMENT}} and updated with every risk assessment ({{RISK_REVIEW_CYCLE}})." + }, + "ISO-MS-BETRIEB": { + "titel": "Operational planning and control", + "umsetzung": "The processes required to meet the information security requirements are laid down in the procedures and controlled in {{TOOL_NAME}}; for each process the trigger, responsible role, deadlines and evidence are defined. Planned changes are controlled and their consequences assessed; unintended changes are reviewed and corrected where necessary. Outsourced processes are determined and monitored through supplier management ({{LINK:R13}}). Evidence of execution as planned is kept in the evidence register ({{LINK:NACHWEISREGISTER}})." + }, + "ISO-MS-MESSUNG": { + "titel": "Monitoring, measurement, analysis and evaluation", + "umsetzung": "For the evaluation of information security performance and the effectiveness of the ISMS it is defined what is measured (metrics sheet in {{TOOL_NAME}}), by which method and data source, at which interval, who measures, when the results are analysed and who analyses them. The metrics cover at least incident handling, vulnerability and patch remediation, recertification of access rights, restore tests, awareness participation and open actions; each metric has a target value and a responsible role. Results and trends feed into the management review {{MGMT_REVIEW_CYCLE}}; a deviation from the target value triggers an action." + }, + "ISO-MS-MGMTREVIEW": { + "titel": "Management review", + "umsetzung": "{{ROLE_MANAGEMENT}} reviews the ISMS at least {{MGMT_REVIEW_CYCLE}} against a fixed agenda (BL-GOV-02). Inputs are at least: status of actions from previous reviews; changes in relevant internal and external issues and in the requirements of interested parties; feedback on information security performance (nonconformities and corrective actions, monitoring and measurement results, audit results, achievement of the information security objectives); feedback from interested parties; results of the risk assessment and status of the risk treatment plan; opportunities for improvement. Outputs are decisions on opportunities for improvement and on any need to change the ISMS, each with a responsible role and a due date. The minutes are retained in {{TOOL_NAME}}." + }, + "ISO-MS-CAPA": { + "titel": "Nonconformity, corrective action and continual improvement", + "umsetzung": "Nonconformities arising from audits, controls, incidents, deviations of metrics and reports are recorded in {{TOOL_NAME}}. For each case the immediate correction and the handling of the consequences are decided, the cause is analysed and it is evaluated whether similar nonconformities exist or could occur elsewhere. Necessary corrective actions are implemented with a responsible role and a due date; their effectiveness is evaluated after the defined effectiveness interval and, where necessary, risks, controls and documents are adjusted. The nature of the nonconformity, the actions taken and the result of the effectiveness review are retained. The suitability, adequacy and effectiveness of the ISMS are continually improved; evidence is provided through metrics and the management review." + }, + "ISO-THREATINTEL": { + "titel": "Threat intelligence", + "umsetzung": "Information on threats is obtained regularly from named sources ({{THREAT_INTEL_SOURCES}}) and evaluated by {{ROLE_IT_LEAD}} for relevance to the organisation's own systems and services. Relevant findings lead to actions in vulnerability and patch management ({{LINK:VA-06}}), to adjustments of monitoring ({{LINK:VA-13}}) or to a new risk assessment. Evaluation and resulting actions are documented in {{TOOL_TICKET}}." + }, + "ISO-BETRIEBSABLAEUFE": { + "titel": "Documented operating procedures", + "umsetzung": "Operating procedures for information processing facilities are documented and accessible to the personnel who carry them out. They cover commissioning and configuration, operation and monitoring, backup, handling of faults, maintenance and decommissioning. The documentation is updated through change management (BL-OPS-09) whenever changes occur and is checked for currency at least {{POLICY_REVIEW_CYCLE}}. Responsible: {{ROLE_IT_LEAD}}." + }, + "ISO-KAPAZITAET": { + "titel": "Capacity management", + "umsetzung": "The utilisation of the relevant resources — compute, memory, storage, network bandwidth, licences and staffing in IT operations — is monitored {{CAPACITY_REVIEW_FREQ}} (BL-OPS-11). Exceeded thresholds raise an alert; future demand is taken into account in projects and significant changes. Capacity constraints that affect the availability requirements are recorded and treated as a risk." + }, + "ISO-DLP": { + "titel": "Data leakage prevention", + "umsetzung": "For systems, networks and devices that process protected information, measures against unauthorised outflow are in place (BL-OPS-12); at least {{DLP_SCOPE}} are covered. The measures follow the classification ({{LINK:R02}}): rules for disclosure, control of transfer channels, restriction of removable media (BL-EP-03) as well as logging and analysis of conspicuous transfers (BL-OPS-04). Detected violations are handled as security events ({{LINK:VA-01}}); where analysis relates to individuals, co-determination rights are observed." + }, + "ISO-ZEITSYNC": { + "titel": "Clock synchronisation", + "umsetzung": "The system clocks of all logging systems are synchronised to {{NTP_SOURCES}} (BL-OPS-10). Deviations are monitored and reported. A uniform time base and time zone is a prerequisite for the analysis of logs ({{LINK:VA-13}}) and for preserving evidence in the event of an incident." + }, + "ISO-DISZIPLIN": { + "titel": "Handling of violations", + "umsetzung": "A graduated, documented process applies to violations of the information security requirements and is communicated in advance. It takes into account the nature and severity of the violation, intent or negligence, repetition and the training status of the person concerned. The process is run by {{ROLE_HR_LEAD}} in coordination with {{ROLE_ISB}}; employment law requirements and co-determination rights are observed. Its application is documented confidentially." + }, + "ISO-PHY-UMWELT": { + "titel": "Environmental protection, utilities, cabling and maintenance", + "umsetzung": "Sites and technical facilities are protected against physical and environmental threats (BL-PHY-03): early fire detection, protection against water and moisture, temperature and humidity monitoring in technical rooms as well as consideration of site-specific hazards. Equipment is sited so that observation, unauthorised access and environmental risks are minimised. Power and air conditioning for critical systems are designed to be uninterruptible and are tested regularly. Power and data cabling is protected against damage and unauthorised access and is documented. Equipment is maintained according to the manufacturer's specifications; maintenance is carried out only by authorised personnel, is planned and recorded, and is supervised where performed externally." + }, + "ISO-PHY-CLEARDESK": { + "titel": "Clear desk and screen lock", + "umsetzung": "Binding rules apply for a clear desk and locked screens (BL-PHY-04): protected documents and media are locked away when unattended; screens are locked when leaving the workplace and lock automatically after {{SESSION_TIMEOUT}}. Printouts are collected immediately and documents no longer required are destroyed according to their protection needs (BL-DEL-01). The rules also apply when working from home and at mobile workplaces ({{LINK:R06}}); compliance is checked on a sample basis." + }, + "ISO-MASKIERUNG": { + "titel": "Data masking and pseudonymisation", + "umsetzung": "Where the full information content is not required for the purpose, data is masked, pseudonymised or anonymised. This applies in particular to test, training and development environments ({{LINK:R11}}), to analyses and to displays with a restricted need for access. Extent and method follow the classification and the data protection requirements ({{LINK:R14}}); whether the link to a person may be restored, and how that is safeguarded, is governed explicitly." + } + } +} \ No newline at end of file diff --git a/seed/isms-vorlagenpaket-v2/_iso_texts_en.json b/seed/isms-vorlagenpaket-v2/_iso_texts_en.json new file mode 100644 index 0000000..465c15c --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_iso_texts_en.json @@ -0,0 +1,485 @@ +{ + "hinweis": "Englische Paraphrasen der ISO/IEC-27001:2022-Anforderungen (keine Normzitate). Struktur (Zuordnung, Bedingungen, Verfahren) kommt aus _iso_crosswalk.json.", + "texte": { + "4.1": { + "title": "Understanding the organisation and its context", + "requirement": "Internal and external issues that affect the ability to achieve the ISMS objectives are determined and kept up to date." + }, + "4.2": { + "title": "Needs of interested parties", + "requirement": "The interested parties relevant to the ISMS and their information security requirements are determined." + }, + "4.3": { + "title": "Scope of the ISMS", + "requirement": "The scope of the ISMS is determined considering the issues, requirements and interfaces, and maintained as documented information." + }, + "4.4": { + "title": "Information security management system", + "requirement": "An ISMS is established, implemented, maintained and continually improved." + }, + "5.1": { + "title": "Leadership and commitment", + "requirement": "Top management demonstrates leadership and commitment with respect to the ISMS." + }, + "5.2": { + "title": "Information security policy", + "requirement": "An information security policy is established that fits the organisation, sets objectives, commits to meeting requirements and to continual improvement, and is communicated and available." + }, + "5.3": { + "title": "Roles, responsibilities and authorities", + "requirement": "Responsibilities and authorities for security-relevant roles are assigned and communicated." + }, + "6.1.1": { + "title": "Actions to address risks and opportunities", + "requirement": "When planning the ISMS, risks and opportunities that need to be addressed are determined." + }, + "6.1.2": { + "title": "Information security risk assessment", + "requirement": "A risk assessment process with defined criteria is established and applied so that it is repeatable and produces comparable results." + }, + "6.1.3": { + "title": "Information security risk treatment", + "requirement": "A risk treatment process is defined; necessary controls are determined and compared against Annex A in a Statement of Applicability." + }, + "6.2": { + "title": "Information security objectives and planning", + "requirement": "Information security objectives are established for relevant functions and levels, and their achievement is planned." + }, + "6.3": { + "title": "Planning of changes", + "requirement": "Changes to the ISMS are carried out in a planned manner." + }, + "7.1": { + "title": "Resources", + "requirement": "The resources needed for the ISMS are determined and provided." + }, + "7.2": { + "title": "Competence", + "requirement": "The necessary competence is determined and ensured; corresponding evidence is retained." + }, + "7.3": { + "title": "Awareness", + "requirement": "Persons under the organisation's control are aware of the policy, their contribution and the consequences of non-conformance." + }, + "7.4": { + "title": "Communication", + "requirement": "The internal and external communications relevant to the ISMS are determined." + }, + "7.5.1": { + "title": "Documented information — general", + "requirement": "The ISMS includes the documented information required by the standard and that determined as necessary." + }, + "7.5.2": { + "title": "Creating and updating", + "requirement": "When creating and updating documented information, identification, format and medium as well as review and approval are ensured." + }, + "7.5.3": { + "title": "Control of documented information", + "requirement": "Documented information is controlled: availability, protection, distribution, access, retention and change control." + }, + "8.1": { + "title": "Operational planning and control", + "requirement": "The processes needed to meet the requirements are planned, implemented and controlled; planned changes are controlled." + }, + "8.2": { + "title": "Information security risk assessment (performance)", + "requirement": "Risk assessments are performed at planned intervals and upon significant change, and are documented." + }, + "8.3": { + "title": "Information security risk treatment (performance)", + "requirement": "The risk treatment plan is implemented and the results are documented." + }, + "9.1": { + "title": "Monitoring, measurement, analysis and evaluation", + "requirement": "The information security performance and the effectiveness of the ISMS are monitored, measured, analysed and evaluated." + }, + "9.2": { + "title": "Internal audit", + "requirement": "Internal audits are conducted at planned intervals to verify conformity and effective implementation of the ISMS." + }, + "9.3": { + "title": "Management review", + "requirement": "Top management reviews the ISMS at planned intervals." + }, + "10.1": { + "title": "Continual improvement", + "requirement": "The suitability, adequacy and effectiveness of the ISMS are continually improved." + }, + "10.2": { + "title": "Nonconformity and corrective action", + "requirement": "In the event of nonconformity, corrections are made and corrective actions are taken to eliminate the causes." + }, + "A.5.1": { + "title": "Policies for information security", + "requirement": "The information security policy and topic-specific policies are defined, approved by management, published, communicated, acknowledged and reviewed at planned intervals." + }, + "A.5.2": { + "title": "Information security roles and responsibilities", + "requirement": "Information security roles and responsibilities are defined and allocated." + }, + "A.5.3": { + "title": "Segregation of duties", + "requirement": "Conflicting duties and areas of responsibility are segregated to reduce unauthorised or unintentional modification and misuse." + }, + "A.5.4": { + "title": "Management responsibilities", + "requirement": "Management requires all personnel to apply information security in accordance with the established requirements." + }, + "A.5.5": { + "title": "Contact with authorities", + "requirement": "Appropriate contacts with relevant authorities are established and maintained." + }, + "A.5.6": { + "title": "Contact with special interest groups", + "requirement": "Appropriate contacts with special interest groups, professional forums and security associations are maintained." + }, + "A.5.7": { + "title": "Threat intelligence", + "requirement": "Information on threats is collected and analysed to produce and use threat intelligence." + }, + "A.5.8": { + "title": "Information security in project management", + "requirement": "Information security is integrated into project management." + }, + "A.5.9": { + "title": "Inventory of information and other associated assets", + "requirement": "An inventory of information and associated assets, including owners, is established and maintained." + }, + "A.5.10": { + "title": "Acceptable use of information and other associated assets", + "requirement": "Rules for the acceptable use and handling of information and assets are defined, documented and implemented." + }, + "A.5.11": { + "title": "Return of assets", + "requirement": "Personnel and external users return all assets in their possession upon termination of employment or contract." + }, + "A.5.12": { + "title": "Classification of information", + "requirement": "Information is classified according to its protection needs (confidentiality, integrity, availability)." + }, + "A.5.13": { + "title": "Labelling of information", + "requirement": "Procedures for labelling information in accordance with the classification scheme are developed and implemented." + }, + "A.5.14": { + "title": "Information transfer", + "requirement": "Rules, procedures and agreements for the secure transfer of information are established for all transfer channels in use." + }, + "A.5.15": { + "title": "Access control", + "requirement": "Rules to control physical and logical access to information and assets are established and implemented on the basis of business and information security requirements." + }, + "A.5.16": { + "title": "Identity management", + "requirement": "The full life cycle of identities is managed." + }, + "A.5.17": { + "title": "Authentication information", + "requirement": "Allocation and management of authentication information is controlled by a suitable management process." + }, + "A.5.18": { + "title": "Access rights", + "requirement": "Access rights are provisioned, reviewed, modified and removed in accordance with the access control policy." + }, + "A.5.19": { + "title": "Information security in supplier relationships", + "requirement": "Processes to manage the information security risks arising from supplier relationships are defined and implemented." + }, + "A.5.20": { + "title": "Addressing information security within supplier agreements", + "requirement": "Relevant information security requirements are agreed with each supplier and recorded contractually." + }, + "A.5.21": { + "title": "Managing information security in the ICT supply chain", + "requirement": "Processes to manage information security risks in the ICT product and service supply chain are defined and implemented." + }, + "A.5.22": { + "title": "Monitoring, review and change management of supplier services", + "requirement": "The information security of supplier services is monitored and reviewed regularly, and changes are managed." + }, + "A.5.23": { + "title": "Information security for use of cloud services", + "requirement": "Processes for acquisition, use, management and exit of cloud services are established in line with the information security requirements." + }, + "A.5.24": { + "title": "Information security incident management planning and preparation", + "requirement": "The management of information security incidents is planned and prepared (roles, processes, responsibilities)." + }, + "A.5.25": { + "title": "Assessment and decision on information security events", + "requirement": "Information security events are assessed and a decision is taken whether they are to be categorised as incidents." + }, + "A.5.26": { + "title": "Response to information security incidents", + "requirement": "Information security incidents are responded to in accordance with documented procedures." + }, + "A.5.27": { + "title": "Learning from information security incidents", + "requirement": "Knowledge gained from information security incidents is used to strengthen the controls." + }, + "A.5.28": { + "title": "Collection of evidence", + "requirement": "Procedures for the identification, collection, acquisition and preservation of evidence relating to incidents are established and implemented." + }, + "A.5.29": { + "title": "Information security during disruption", + "requirement": "The maintenance of information security during disruption is planned and implemented." + }, + "A.5.30": { + "title": "ICT readiness for business continuity", + "requirement": "ICT readiness is planned, implemented and tested on the basis of the business continuity objectives and requirements." + }, + "A.5.31": { + "title": "Legal, statutory, regulatory and contractual requirements", + "requirement": "Legal, statutory, regulatory and contractual information security requirements are identified, documented and kept up to date." + }, + "A.5.32": { + "title": "Intellectual property rights", + "requirement": "Appropriate procedures to protect intellectual property rights are implemented." + }, + "A.5.33": { + "title": "Protection of records", + "requirement": "Records are protected against loss, destruction, falsification, unauthorised access and unauthorised release." + }, + "A.5.34": { + "title": "Privacy and protection of PII", + "requirement": "Requirements for the protection of personally identifiable information are identified and met in accordance with applicable obligations." + }, + "A.5.35": { + "title": "Independent review of information security", + "requirement": "The organisation's approach to managing information security is reviewed independently at planned intervals." + }, + "A.5.36": { + "title": "Compliance with policies, rules and standards for information security", + "requirement": "Compliance with the information security policy, topic-specific policies, rules and standards is reviewed regularly." + }, + "A.5.37": { + "title": "Documented operating procedures", + "requirement": "Operating procedures for information processing facilities are documented and made available to the personnel concerned." + }, + "A.6.1": { + "title": "Screening", + "requirement": "Background verification of candidates is carried out appropriately to the business requirements and in accordance with the law." + }, + "A.6.2": { + "title": "Terms and conditions of employment", + "requirement": "The employment agreements state the responsibilities for information security." + }, + "A.6.3": { + "title": "Information security awareness, education and training", + "requirement": "Personnel receive appropriate awareness, education and training as well as regular updates of the relevant policies." + }, + "A.6.4": { + "title": "Disciplinary process", + "requirement": "A disciplinary process for information security violations is established and communicated." + }, + "A.6.5": { + "title": "Responsibilities after termination or change of employment", + "requirement": "Continuing information security responsibilities after termination or change of employment are defined and enforced." + }, + "A.6.6": { + "title": "Confidentiality or non-disclosure agreements", + "requirement": "Confidentiality or non-disclosure agreements are identified, documented and reviewed regularly." + }, + "A.6.7": { + "title": "Remote working", + "requirement": "Security measures for working outside the organisation's premises are implemented." + }, + "A.6.8": { + "title": "Information security event reporting", + "requirement": "A mechanism for the timely reporting of observed or suspected information security events is provided." + }, + "A.7.1": { + "title": "Physical security perimeters", + "requirement": "Security perimeters are defined and used to protect areas containing information and assets." + }, + "A.7.2": { + "title": "Physical entry", + "requirement": "Secure entry controls and entry points are established to restrict access to authorised persons." + }, + "A.7.3": { + "title": "Securing offices, rooms and facilities", + "requirement": "Physical security for offices, rooms and facilities is designed and implemented." + }, + "A.7.4": { + "title": "Physical security monitoring", + "requirement": "Premises are continuously monitored for unauthorised physical access." + }, + "A.7.5": { + "title": "Protecting against physical and environmental threats", + "requirement": "Protection against physical and environmental threats is designed and implemented." + }, + "A.7.6": { + "title": "Working in secure areas", + "requirement": "Measures for working in secure areas are defined and implemented." + }, + "A.7.7": { + "title": "Clear desk and clear screen", + "requirement": "Rules for a clear desk and locked screens are defined and implemented." + }, + "A.7.8": { + "title": "Equipment siting and protection", + "requirement": "Equipment is sited securely and protected." + }, + "A.7.9": { + "title": "Security of assets off-premises", + "requirement": "Assets used outside the premises are protected." + }, + "A.7.10": { + "title": "Storage media", + "requirement": "Storage media are protected throughout their life cycle (acquisition, use, transport, disposal) in accordance with the classification scheme." + }, + "A.7.11": { + "title": "Supporting utilities", + "requirement": "Facilities are protected against failure and disruption of supporting utilities such as power and air conditioning." + }, + "A.7.12": { + "title": "Cabling security", + "requirement": "Power and data cabling is protected against interception, interference and damage." + }, + "A.7.13": { + "title": "Equipment maintenance", + "requirement": "Equipment is maintained properly to ensure availability and integrity." + }, + "A.7.14": { + "title": "Secure disposal or re-use of equipment", + "requirement": "Equipment containing storage media is securely sanitised before disposal or re-use." + }, + "A.8.1": { + "title": "User endpoint devices", + "requirement": "Information stored on, processed by or accessible via user endpoint devices is protected." + }, + "A.8.2": { + "title": "Privileged access rights", + "requirement": "The allocation and use of privileged access rights is restricted and closely managed." + }, + "A.8.3": { + "title": "Information access restriction", + "requirement": "Access to information and application functions is restricted in accordance with the access control policy." + }, + "A.8.4": { + "title": "Access to source code", + "requirement": "Read and write access to source code, development tools and software libraries is appropriately managed." + }, + "A.8.5": { + "title": "Secure authentication", + "requirement": "Secure authentication technologies and procedures are used on the basis of the access restrictions and the access control policy." + }, + "A.8.6": { + "title": "Capacity management", + "requirement": "Resources are monitored and capacity is adjusted to current and expected demand." + }, + "A.8.7": { + "title": "Protection against malware", + "requirement": "Protection against malware is implemented and supported by appropriate user awareness." + }, + "A.8.8": { + "title": "Management of technical vulnerabilities", + "requirement": "Information on technical vulnerabilities is obtained, exposure is evaluated and appropriate measures are taken." + }, + "A.8.9": { + "title": "Configuration management", + "requirement": "Configurations of hardware, software, services and networks are established, documented, implemented, monitored and reviewed." + }, + "A.8.10": { + "title": "Information deletion", + "requirement": "Information stored in systems and on media is deleted when no longer required." + }, + "A.8.11": { + "title": "Data masking", + "requirement": "Data masking is applied in accordance with the access control and privacy requirements." + }, + "A.8.12": { + "title": "Data leakage prevention", + "requirement": "Measures to prevent data leakage are applied to systems, networks and devices that process sensitive information." + }, + "A.8.13": { + "title": "Information backup", + "requirement": "Backup copies of information, software and systems are created in accordance with the backup concept and tested regularly." + }, + "A.8.14": { + "title": "Redundancy of information processing facilities", + "requirement": "Information processing facilities are implemented with sufficient redundancy to meet the availability requirements." + }, + "A.8.15": { + "title": "Logging", + "requirement": "Logs of activities, exceptions, faults and events are produced, stored, protected and analysed." + }, + "A.8.16": { + "title": "Monitoring activities", + "requirement": "Networks, systems and applications are monitored for anomalous behaviour and potential incidents are evaluated." + }, + "A.8.17": { + "title": "Clock synchronisation", + "requirement": "System clocks are synchronised to approved time sources." + }, + "A.8.18": { + "title": "Use of privileged utility programs", + "requirement": "The use of utility programs capable of overriding system and application controls is restricted and tightly controlled." + }, + "A.8.19": { + "title": "Installation of software on operational systems", + "requirement": "Procedures and measures for securely managing software installation on operational systems are implemented." + }, + "A.8.20": { + "title": "Networks security", + "requirement": "Networks and network devices are secured, managed and controlled to protect information." + }, + "A.8.21": { + "title": "Security of network services", + "requirement": "Security mechanisms, service levels and requirements for network services are identified, implemented and monitored." + }, + "A.8.22": { + "title": "Segregation of networks", + "requirement": "Groups of information services, users and systems are segregated in networks." + }, + "A.8.23": { + "title": "Web filtering", + "requirement": "Access to external websites is managed to reduce exposure to malicious content." + }, + "A.8.24": { + "title": "Use of cryptography", + "requirement": "Rules for the effective use of cryptography, including key management, are defined and implemented." + }, + "A.8.25": { + "title": "Secure development life cycle", + "requirement": "Rules for a secure development life cycle of software and systems are established and applied." + }, + "A.8.26": { + "title": "Application security requirements", + "requirement": "Information security requirements are identified, specified and taken into account when developing or acquiring applications." + }, + "A.8.27": { + "title": "Secure system architecture and engineering principles", + "requirement": "Principles for engineering secure systems are established, documented and applied." + }, + "A.8.28": { + "title": "Secure coding", + "requirement": "Secure coding principles are applied to software development." + }, + "A.8.29": { + "title": "Security testing in development and acceptance", + "requirement": "Security testing is integrated into the development and acceptance process." + }, + "A.8.30": { + "title": "Outsourced development", + "requirement": "Outsourced system development is directed, monitored and reviewed." + }, + "A.8.31": { + "title": "Separation of development, test and production environments", + "requirement": "Development, test and production environments are separated and protected." + }, + "A.8.32": { + "title": "Change management", + "requirement": "Changes to information processing facilities and systems are subject to change management." + }, + "A.8.33": { + "title": "Test information", + "requirement": "Test information is selected, protected and managed with care." + }, + "A.8.34": { + "title": "Protection of information systems during audit testing", + "requirement": "Audit tests and similar activities on operational systems are planned and agreed to avoid disruption." + } + } +} \ No newline at end of file diff --git a/seed/isms-vorlagenpaket-v2/_matrix.py b/seed/isms-vorlagenpaket-v2/_matrix.py new file mode 100644 index 0000000..8bc9413 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_matrix.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import json, collections, os +BASE=os.path.dirname(__file__) +d=json.load(open(os.path.join(BASE,"mapping.json"),encoding="utf-8")) +POLTITLE={"L00":"Informationssicherheitsleitlinie","R01":"ISMS-Organisation und Rollen","R02":"Asset- und Klassifizierung","R03":"Risikomanagement und Audit","R04":"Incident, Notfall und Kontinuität","R05":"Personalsicherheit und Awareness","R06":"Mobiles Arbeiten und mobile Geräte","R07":"Physische Sicherheit","R08":"Identitäts- und Zugriffsmanagement","R09":"Kryptografie und Übertragung","R10":"Betriebssicherheit","R11":"Sichere Beschaffung und Entwicklung","R12":"Cloud-, KI- und externe IT-Dienste","R13":"Lieferanten- und Dienstleistersteuerung","R14":"Compliance und Datenschutz"} +by=collections.OrderedDict() +for a in d["anforderungen"]: + by.setdefault(a["control"],[]).append(a) +def cnt(items,t): return sum(1 for x in items if x["type"]==t) +L=[] +L.append("# ISA-Mapping-Matrix - VDA ISA 2027 (Information Security)\n") +L.append("Zentrale Zuordnung **ISA-Control -> Richtlinie -> Einzelanforderungen** über alle Schutzbedarf-Ebenen (MUSS/SOLL/HOCH/SEHR HOCH). Anforderungen 1:1 aus der ISA übernommen; Kopplung über `mapping.json` und Hidden-Anker. Verweise: {{LINK:NACHWEISREGISTER}}, {{LINK:BASELINE}}.\n") +L.append("| ISA | Richtlinie | MUSS | SOLL | HOCH | SEHR HOCH | Verfahren |") +L.append("|-----|-----------|------|------|------|-----------|-----------|") +va_by_ctrl=collections.defaultdict(set) +for v in d.get("verfahren",[]): + for f in v["fulfills"]: + ctrl=f.rsplit("-",1)[0] + va_by_ctrl[ctrl].add(v["id"]) +for ctrl,items in by.items(): + pol=items[0]["policy"] + va=", ".join(sorted(va_by_ctrl.get(ctrl,[]))) or "-" + L.append(f"| {ctrl} | {{{{LINK:{pol}}}}} {POLTITLE.get(pol,pol)} | {cnt(items,'MUSS')} | {cnt(items,'SOLL')} | {cnt(items,'HOCH')} | {cnt(items,'SEHR HOCH')} | {va} |") +tot=collections.Counter(a["type"] for a in d["anforderungen"]) +isa=sum(1 for a in d["anforderungen"] if a.get("is_isa")) +cust=sum(1 for a in d["anforderungen"] if not a.get("is_isa")) +L.append(f"\n**Summe:** {len(d['anforderungen'])} Anforderungen (MUSS {tot['MUSS']}, SOLL {tot['SOLL']}, HOCH {tot['HOCH']}, SEHR HOCH {tot['SEHR HOCH']}) — davon {isa} 1:1 aus VDA ISA und {cust} kundenspezifische Ergänzung (KI). Controls: {len(by)}.\n") +L.append("> 3.1.2 in ISA 2027 als 'Superseded by 1.6.3, 5.2.8 und 5.2.9' entfallen - abgedeckt über {{LINK:R04}} und {{LINK:R10}}.\n") +L.append("## Detailzuordnung je Anforderung\n") +L.append("| ID | Ebene | Richtlinie | Anforderung (Kurz) | Bedingung |") +L.append("|----|-------|-----------|--------------------|-----------|") +for a in d["anforderungen"]: + req=a["requirement"].replace("|","/"); req=(req[:90]+"...") if len(req)>90 else req + L.append(f"| {a['id']} | {a['type']} | {a['policy']} | {req} | {a['condition'] or '-'} |") +open(os.path.join(BASE,"ISA-Mapping-Matrix.md"),"w",encoding="utf-8").write("\n".join(L)) +print("Matrix ok. Anforderungen:",len(d["anforderungen"]),"Controls:",len(by)) diff --git a/seed/isms-vorlagenpaket-v2/_render_diff.py b/seed/isms-vorlagenpaket-v2/_render_diff.py new file mode 100644 index 0000000..d43d8b5 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_render_diff.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +""" +Regressionsschutz: Rendert alle Richtlinien in einer Framework-Sicht und vergleicht das +Ergebnis mit einem Git-Stand. Erwartung fuer TISAX: 0 Abweichungen. + + python3 _render_diff.py [--framework TISAX|ISO|BEIDE] + +Beispiele: + python3 _render_diff.py a9649b3 # TISAX-Sicht gegen den Stand vor dem ISO-Umbau + python3 _render_diff.py dev --framework ISO # ISO-Sicht gegen dev + +Verglichen wird der gerenderte Text ohne Leerzeilen und ohne Kommentar-Anker — also das, +was ein Mandant tatsaechlich zu sehen bekommt. +""" +import difflib, glob, json, os, re, subprocess, sys + +BASE = os.path.dirname(os.path.abspath(__file__)) +REPO = subprocess.run(["git", "rev-parse", "--show-toplevel"], cwd=BASE, + capture_output=True, text=True).stdout.strip() + +if len(sys.argv) < 2: + print(__doc__); sys.exit(2) +REV = sys.argv[1] +FW = "TISAX" +if "--framework" in sys.argv: + FW = sys.argv[sys.argv.index("--framework") + 1].upper() + +schema = json.load(open(os.path.join(BASE, "variables.schema.json"), encoding="utf-8")) + + +def ctx(): + c = {k: (True if k.startswith("FLAG_") else "{%s}" % k) for k in schema["properties"]} + for k in ["FLAG_OT_USED", "FLAG_DEV_INHOUSE", "FLAG_CRYPTO_PKI", "FLAG_CUSTOMER_SYSTEMS"]: + c[k] = False + c["FLAG_FW_TISAX"] = FW in ("TISAX", "BEIDE") + c["FLAG_FW_ISO27001"] = FW in ("ISO", "BEIDE") + return c + + +def render(txt, c): + pat = re.compile(r"\{\{#if (\w+)\}\}((?:(?!\{\{#if )(?!\{\{/if\}\}).)*?)\{\{/if\}\}", re.S) + prev = None + while prev != txt: + prev = txt + txt = pat.sub(lambda m: (m.group(2) if c.get(m.group(1)) else ""), txt) + txt = re.sub(r"", "", txt, flags=re.S) + txt = re.sub(r"\{\{LINK:([^}]+)\}\}", r"[\1]", txt) + txt = re.sub(r"\{\{(\w+)\}\}", lambda m: str(c.get(m.group(1), "?")), txt) + return [l.rstrip() for l in txt.split("\n") if l.strip()] + + +def at_rev(relpath): + r = subprocess.run(["git", "show", "%s:%s" % (REV, relpath)], cwd=REPO, + capture_output=True, text=True) + return r.stdout if r.returncode == 0 else None + + +c = ctx() +drift, missing, checked = 0, 0, 0 +for path in sorted(glob.glob(os.path.join(BASE, "richtlinien", "*.md"))): + rel = os.path.relpath(path, REPO) + old_raw = at_rev(rel) + if old_raw is None: + missing += 1 + print(" neu in dieser Fassung:", os.path.basename(path)) + continue + checked += 1 + old, new = render(old_raw, c), render(open(path, encoding="utf-8").read(), c) + if old != new: + drift += 1 + print("ABWEICHUNG:", os.path.basename(path)) + for line in list(difflib.unified_diff(old, new, lineterm="", n=0))[:10]: + print(" ", line[:140]) + +print() +print("Sicht: %s · Vergleichsstand: %s" % (FW, REV)) +print("geprueft: %d Richtlinien, neu: %d, abweichend: %d" % (checked, missing, drift)) +print("OK" if drift == 0 else "PRUEFEN") +sys.exit(0 if drift == 0 else 1) diff --git a/seed/isms-vorlagenpaket-v2/_verify.py b/seed/isms-vorlagenpaket-v2/_verify.py new file mode 100644 index 0000000..2790e15 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_verify.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# Korrekter rekursiver {{#if}}-Renderer (wie echtes Handlebars) zur Verifikation. +import re, glob, json, os +BASE=os.path.dirname(__file__) +schema=json.load(open(os.path.join(BASE,"variables.schema.json"))) +allvars=set(schema["properties"].keys()) + +def make_ctx(inc, extra=None): + c={k:(True if k.startswith("FLAG_") else k) for k in allvars} + for k in ["FLAG_OT_USED","FLAG_DEV_INHOUSE","FLAG_CRYPTO_PKI","FLAG_CUSTOMER_SYSTEMS"]: c[k]=False + c["FLAG_INCLUDE_SHOULD"]=inc + c["ORG_NAME"]="Muster GmbH"; c["TOOL_NAME"]="ISMS-Portal"; c["REVIEW_CYCLE"]="jährlich" + c["FLAG_FW_TISAX"]=True; c["FLAG_FW_ISO27001"]=False # dieses Skript prueft die TISAX-Sicht + if extra: c.update(extra) + return c + +def render_if(t,c): + # rekursiv innerste Bloecke zuerst + pat=re.compile(r"\{\{#if (\w+)\}\}((?:(?!\{\{#if )(?!\{\{/if\}\}).)*?)\{\{/if\}\}",re.S) + prev=None + while prev!=t: + prev=t + t=pat.sub(lambda m:(m.group(2) if c.get(m.group(1)) else ""),t) + return t + +def render(t,c): + t=render_if(t,c) + t=re.sub(r"\{\{LINK:[^}]+\}\}","[LINK]",t) + t=re.sub(r"\{\{(\w+)\}\}",lambda m:str(c[m.group(1)]) if m.group(1) in c else "«MISS:%s»"%m.group(1),t) + return t + +files=sorted(glob.glob(os.path.join(BASE,"richtlinien/*.md")))+[os.path.join(BASE,"Nachweisregister_zentral.md"),os.path.join(BASE,"ISA-Mapping-Matrix.md")] +problems=0 +for inc in [True,False]: + c=make_ctx(inc) + for fp in files: + r=render(open(fp,encoding="utf-8").read(),c) + bad=re.findall(r"\{\{.*?\}\}",r); miss=sorted(set(re.findall(r"«MISS:\w+»",r))) + if bad or miss: + problems+=1; print("!",os.path.basename(fp),"inc=%s"%inc,"open:",bad[:4],"miss:",miss[:4]) +# Zwei Framework-Mappings teilen sich diese Bibliothek: die Anker des ISO-Mappings +# werden hier ausgeblendet und von _verify_iso.py geprueft. +iso_anchors=set() +_iso=os.path.join(BASE,"mapping-iso.json") +if os.path.exists(_iso): + for a in json.load(open(_iso,encoding="utf-8"))["anforderungen"]: + iso_anchors.add(a["req_anchor"]); iso_anchors.add(a["impl_anchor"]) +d=json.load(open(os.path.join(BASE,"mapping.json"))) +fa=set() +for fp in glob.glob(os.path.join(BASE,"richtlinien/*.md")): + for m in re.findall(r"",open(fp,encoding="utf-8").read()): fa.add(m[0]+" "+m[1]) +ma=set() +for a in d["anforderungen"]: ma.add(a["req_anchor"]); ma.add(a["impl_anchor"]) +fa-=(iso_anchors-ma) # nur ISO-exklusive Anker ausblenden; gemeinsam genutzte bleiben geprueft +# F17: mapping.json enthaelt kein 'implementation'-Feld; der Umsetzungstext wird zur +# Laufzeit ueber impl_anchor (Control-IMPL-Block) aus der jeweiligen .md aufgeloest. +leftover_hb=any("{{" in a["requirement"] or "{{" in a.get("implementation","") for a in d["anforderungen"]) +print("Render-Probleme:",problems) +print("mapping-Anker ohne Datei:",sorted(ma-fa)) +print("Datei-Anker ohne mapping:",sorted(fa-ma)) +print("Handlebars-Reste in mapping-Text:",leftover_hb) +print("OK" if problems==0 and not (ma-fa) and not (fa-ma) and not leftover_hb else "PRUEFEN") diff --git a/seed/isms-vorlagenpaket-v2/_verify_iso.py b/seed/isms-vorlagenpaket-v2/_verify_iso.py new file mode 100644 index 0000000..86e953d --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/_verify_iso.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +""" +Prueft die ISO/IEC-27001-Sicht der gemeinsamen Dokumentenbibliothek. + +Gegenstueck zu _verify.py (das die TISAX-Sicht prueft). Geprueft wird: + 1. Vollstaendigkeit — 27 Klauseln (Kap. 4-10) + 93 Anhang-A-Controls, keine Luecke, keine Dublette + 2. Anker — jeder req_anchor/impl_anchor aus mapping-iso.json existiert in einer Datei + 3. Umsetzungstext — jeder impl_anchor loest auf einen nicht leeren Umsetzungsblock auf + 4. Rendering — ISO-Sicht (FLAG_FW_ISO27001=True, FLAG_FW_TISAX=False) bleibt ohne + offene Platzhalter; ebenso die TISAX-Sicht (Regressionsschutz) + 5. Verfahren — jede im Mapping genannte VA existiert und listet die ID im FULFILLS-Header + +Aufruf: python3 _verify_iso.py +""" +import re, glob, json, os, sys + +BASE = os.path.dirname(os.path.abspath(__file__)) +LANG = sys.argv[sys.argv.index("--lang") + 1] if "--lang" in sys.argv else "de" +# Dieselbe Prüfung gilt für beide Sprachfassungen; nur das Verzeichnis wechselt. +PKG = BASE if LANG == "de" else os.path.normpath(os.path.join(BASE, "..", "isms-vorlagenpaket-v2-en")) +schema = json.load(open(os.path.join(PKG, "variables.schema.json"), encoding="utf-8")) +allvars = set(schema["properties"].keys()) +mapping = json.load(open(os.path.join(PKG, "mapping-iso.json"), encoding="utf-8")) +reqs = mapping["anforderungen"] +problems = [] + + +def ctx(framework): + c = {k: (True if k.startswith("FLAG_") else k) for k in allvars} + for k in ["FLAG_OT_USED", "FLAG_DEV_INHOUSE", "FLAG_CRYPTO_PKI", "FLAG_CUSTOMER_SYSTEMS"]: + c[k] = False + c["ORG_NAME"] = "Muster GmbH"; c["TOOL_NAME"] = "ISMS-Portal"; c["REVIEW_CYCLE"] = "jährlich" + c["FLAG_FW_ISO27001"] = framework == "ISO" + c["FLAG_FW_TISAX"] = framework == "TISAX" + return c + + +def render(t, c): + pat_if = re.compile(r"\{\{#if (\w+)\}\}((?:(?!\{\{#if )(?!\{\{#unless )(?!\{\{/if\}\}).)*?)\{\{/if\}\}", re.S) + pat_un = re.compile(r"\{\{#unless (\w+)\}\}((?:(?!\{\{#unless )(?!\{\{/unless\}\}).)*?)\{\{/unless\}\}", re.S) + prev = None + while prev != t: + prev = t + t = pat_if.sub(lambda m: (m.group(2) if c.get(m.group(1)) else ""), t) + t = pat_un.sub(lambda m: ("" if c.get(m.group(1)) else m.group(2)), t) + t = re.sub(r"\{\{LINK:[^}]+\}\}", "[LINK]", t) + t = re.sub(r"\{\{(\w+)\}\}", lambda m: str(c[m.group(1)]) if m.group(1) in c else "«MISS:%s»" % m.group(1), t) + return t + + +# ── 1. Vollstaendigkeit ─────────────────────────────────────────────────────── +clauses = [r["control"] for r in reqs if r["kind"] == "clause"] +controls = [r["control"] for r in reqs if r["kind"] != "clause"] +EXPECT = {"5": 37, "6": 8, "7": 14, "8": 34} +if len(clauses) != 27: + problems.append("Klausel-Anforderungen: %d statt 27" % len(clauses)) +if len(controls) != 93: + problems.append("Anhang-A-Controls: %d statt 93" % len(controls)) +for grp, n in EXPECT.items(): + have = sorted(int(c.split(".")[2]) for c in controls if c.split(".")[1] == grp) + miss = [i for i in range(1, n + 1) if i not in have] + if miss: + problems.append("A.%s fehlt: %s" % (grp, miss)) + if len(have) != len(set(have)): + problems.append("A.%s enthaelt Dubletten" % grp) + +# ── 2./3. Anker und Umsetzungstext ──────────────────────────────────────────── +impl_text, file_anchors = {}, set() +for fp in glob.glob(os.path.join(PKG, "richtlinien", "*.md")): + lines = open(fp, encoding="utf-8").read().split("\n") + for i, ln in enumerate(lines): + m = re.match(r"^$", ln.strip()) + if not m: + continue + file_anchors.add("%s %s" % (m.group(1), m.group(2))) + if m.group(1) == "IMPL": + buf = [] + for l in lines[i + 1:]: + t = l.strip() + if t == "" or t.startswith("", open(fp, encoding="utf-8").read()) + va_fulfills[code] = [x.strip() for x in m.group(1).split(",")] if m else [] +for r in reqs: + for va in r["verfahren"]: + if va not in va_fulfills: + problems.append("%s: Verfahren %s existiert nicht" % (r["control"], va)) + elif r["id"] not in va_fulfills[va]: + problems.append("%s: %s fehlt im FULFILLS-Header von %s" % (r["control"], r["id"], va)) + +# ── Ergebnis ────────────────────────────────────────────────────────────────── +pol = {} +for r in reqs: + pol.setdefault(r["policy"], []).append(r["control"]) +print("Sprache: %s" % LANG.upper()) +print("Anforderungen: %d (%d Klauseln + %d Controls)" % (len(reqs), len(clauses), len(controls))) +print("Richtlinien: %s" % ", ".join("%s=%d" % (k, len(v)) for k, v in sorted(pol.items()))) +print("Umsetzungsblöcke: %d referenziert, davon %d gemeinsam mit VDA ISA" + % (len({r["impl_anchor"] for r in reqs}), + len({r["impl_anchor"] for r in reqs if not r["impl_anchor"].startswith("IMPL ISO-")}))) +print("Verfahren verknüpft:%d Anforderungen" % sum(1 for r in reqs if r["verfahren"])) +print("Befunde: %d" % len(problems)) +for p in problems[:25]: + print(" !", p) +print("OK" if not problems else "PRUEFEN") +sys.exit(0 if not problems else 1) diff --git a/seed/isms-vorlagenpaket-v2/mapping-iso.json b/seed/isms-vorlagenpaket-v2/mapping-iso.json new file mode 100644 index 0000000..5f12a60 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/mapping-iso.json @@ -0,0 +1,2219 @@ +{ + "meta": { + "paket": "ISMS-Vorlagenpaket v2 — Framework-Mapping ISO/IEC 27001:2022", + "standard": "ISO/IEC 27001:2022 (Kap. 4-10 + Anhang A)", + "framework": "ISO_27001", + "version": "2.1", + "bibliothek": "gemeinsam mit dem VDA-ISA-Mapping (mapping.json) — ein Dokumentensatz, zwei Mappings", + "hinweis": "Anforderungstexte sind eigene Paraphrasen (keine woertlichen Normzitate); die Referenzen sind exakt zum Nachschlagen. Der Umsetzungstext wird ueber impl_anchor aus dem jeweiligen Richtlinienabschnitt aufgeloest und ist mit dem VDA-ISA-Mapping geteilt.", + "coverage": "27 Klausel-Anforderungen (Kap. 4-10) + 93 Anhang-A-Controls = 120 Eintraege" + }, + "anforderungen": [ + { + "id": "4.1-1", + "policy": "R01", + "control": "4.1", + "kind": "clause", + "title": "Verstehen der Organisation und ihres Kontexts", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.1-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "Interne und externe Themen, die die Fähigkeit zur Erreichung der ISMS-Ziele beeinflussen, sind zu bestimmen und aktuell zu halten.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2-1", + "policy": "R01", + "control": "4.2", + "kind": "clause", + "title": "Anforderungen interessierter Parteien", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.2-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "Die für das ISMS relevanten interessierten Parteien und deren Anforderungen an die Informationssicherheit sind zu ermitteln.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.3-1", + "policy": "R01", + "control": "4.3", + "kind": "clause", + "title": "Anwendungsbereich des ISMS", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.3-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "Der Anwendungsbereich des ISMS ist unter Berücksichtigung der Themen, Anforderungen und Schnittstellen festzulegen und als dokumentierte Information zu führen.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.4-1", + "policy": "R01", + "control": "4.4", + "kind": "clause", + "title": "Informationssicherheits-Managementsystem", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 4.4-1", + "impl_anchor": "IMPL ISO-MS-KONTEXT", + "requirement": "Ein ISMS ist einzurichten, umzusetzen, aufrechtzuerhalten und fortlaufend zu verbessern.", + "link": "{{LINK:R01#ISO-MS-KONTEXT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1-1", + "policy": "R01", + "control": "5.1", + "kind": "clause", + "title": "Führung und Verpflichtung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 5.1-1", + "impl_anchor": "IMPL 1.2.1", + "requirement": "Die oberste Leitung hat Führung und Verpflichtung in Bezug auf das ISMS nachzuweisen.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2-1", + "policy": "L00", + "control": "5.2", + "kind": "clause", + "title": "Politik", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 5.2-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "Die oberste Leitung hat eine Informationssicherheitspolitik festzulegen, die zum Zweck der Organisation passt und Ziele bzw. einen Rahmen dafür enthält.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.3-1", + "policy": "R01", + "control": "5.3", + "kind": "clause", + "title": "Rollen, Verantwortlichkeiten und Befugnisse", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 5.3-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Verantwortlichkeiten und Befugnisse für sicherheitsrelevante Rollen sind zuzuweisen und bekannt zu machen.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-1", + "policy": "R03", + "control": "6.1.1", + "kind": "clause", + "title": "Maßnahmen zum Umgang mit Risiken und Chancen", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.1.1-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "Bei der Planung des ISMS sind Risiken und Chancen zu bestimmen, die zu behandeln sind.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "6.1.2-1", + "policy": "R03", + "control": "6.1.2", + "kind": "clause", + "title": "Informationssicherheits-Risikobeurteilung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.1.2-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "Ein Prozess zur Risikobeurteilung mit definierten Kriterien, Wiederholbarkeit und vergleichbaren Ergebnissen ist festzulegen und anzuwenden.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "6.1.3-1", + "policy": "R03", + "control": "6.1.3", + "kind": "clause", + "title": "Informationssicherheits-Risikobehandlung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.1.3-1", + "impl_anchor": "IMPL ISO-SOA", + "requirement": "Ein Risikobehandlungsprozess ist festzulegen; erforderliche Controls sind zu bestimmen und mit Annex A abzugleichen (Statement of Applicability).", + "link": "{{LINK:R03#ISO-SOA}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "6.2-1", + "policy": "L00", + "control": "6.2", + "kind": "clause", + "title": "Informationssicherheitsziele und Planung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.2-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "Informationssicherheitsziele sind für relevante Funktionen und Ebenen festzulegen und deren Erreichung zu planen.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.3-1", + "policy": "R01", + "control": "6.3", + "kind": "clause", + "title": "Planung von Änderungen", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 6.3-1", + "impl_anchor": "IMPL ISO-MS-CHANGE", + "requirement": "Änderungen am ISMS sind geplant durchzuführen.", + "link": "{{LINK:R01#ISO-MS-CHANGE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.1-1", + "policy": "R01", + "control": "7.1", + "kind": "clause", + "title": "Ressourcen", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.1-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Die für das ISMS erforderlichen Ressourcen sind zu bestimmen und bereitzustellen.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.2-1", + "policy": "R05", + "control": "7.2", + "kind": "clause", + "title": "Kompetenz", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.2-1", + "impl_anchor": "IMPL 2.1.1", + "requirement": "Erforderliche Kompetenzen sind zu bestimmen und sicherzustellen; entsprechende Nachweise sind zu führen.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.3-1", + "policy": "R05", + "control": "7.3", + "kind": "clause", + "title": "Bewusstsein", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.3-1", + "impl_anchor": "IMPL 2.1.3", + "requirement": "Personen unter Aufsicht der Organisation müssen sich der Politik, ihres Beitrags und der Folgen von Verstößen bewusst sein.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "7.4-1", + "policy": "L00", + "control": "7.4", + "kind": "clause", + "title": "Kommunikation", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.4-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "Die für das ISMS relevante interne und externe Kommunikation ist zu bestimmen.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.5.1-1", + "policy": "R01", + "control": "7.5.1", + "kind": "clause", + "title": "Dokumentierte Information – Allgemeines", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.5.1-1", + "impl_anchor": "IMPL ISO-MS-DOKU", + "requirement": "Das ISMS muss die von der Norm geforderte und die als notwendig bestimmte dokumentierte Information enthalten.", + "link": "{{LINK:R01#ISO-MS-DOKU}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.5.2-1", + "policy": "R01", + "control": "7.5.2", + "kind": "clause", + "title": "Erstellen und Aktualisieren", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.5.2-1", + "impl_anchor": "IMPL ISO-MS-DOKU", + "requirement": "Bei Erstellung und Aktualisierung dokumentierter Information sind Kennzeichnung, Format/Medium und Prüfung/Freigabe sicherzustellen.", + "link": "{{LINK:R01#ISO-MS-DOKU}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.5.3-1", + "policy": "R01", + "control": "7.5.3", + "kind": "clause", + "title": "Lenkung dokumentierter Information", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 7.5.3-1", + "impl_anchor": "IMPL ISO-MS-DOKU", + "requirement": "Dokumentierte Information ist zu lenken (Verfügbarkeit, Schutz, Verteilung, Zugriff, Aufbewahrung, Änderungssteuerung).", + "link": "{{LINK:R01#ISO-MS-DOKU}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "8.1-1", + "policy": "R03", + "control": "8.1", + "kind": "clause", + "title": "Betriebliche Planung und Steuerung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 8.1-1", + "impl_anchor": "IMPL ISO-MS-BETRIEB", + "requirement": "Die zur Erfüllung der Anforderungen nötigen Prozesse sind zu planen, umzusetzen und zu steuern; geplante Änderungen sind zu kontrollieren.", + "link": "{{LINK:R03#ISO-MS-BETRIEB}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "8.2-1", + "policy": "R03", + "control": "8.2", + "kind": "clause", + "title": "Informationssicherheits-Risikobeurteilung (Durchführung)", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 8.2-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "Risikobeurteilungen sind in geplanten Abständen und bei wesentlichen Änderungen durchzuführen und zu dokumentieren.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "8.3-1", + "policy": "R03", + "control": "8.3", + "kind": "clause", + "title": "Informationssicherheits-Risikobehandlung (Durchführung)", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 8.3-1", + "impl_anchor": "IMPL 1.4.1", + "requirement": "Der Risikobehandlungsplan ist umzusetzen; die Ergebnisse sind zu dokumentieren.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "9.1-1", + "policy": "R03", + "control": "9.1", + "kind": "clause", + "title": "Überwachung, Messung, Analyse und Bewertung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 9.1-1", + "impl_anchor": "IMPL ISO-MS-MESSUNG", + "requirement": "Die Informationssicherheitsleistung und die Wirksamkeit des ISMS sind zu überwachen, zu messen, zu analysieren und zu bewerten.", + "link": "{{LINK:R03#ISO-MS-MESSUNG}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-22" + ] + }, + { + "id": "9.2-1", + "policy": "R03", + "control": "9.2", + "kind": "clause", + "title": "Internes Audit", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 9.2-1", + "impl_anchor": "IMPL 1.5.2", + "requirement": "Interne Audits sind in geplanten Abständen durchzuführen, um die Konformität und wirksame Umsetzung des ISMS zu prüfen.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "9.3-1", + "policy": "R03", + "control": "9.3", + "kind": "clause", + "title": "Managementbewertung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 9.3-1", + "impl_anchor": "IMPL ISO-MS-MGMTREVIEW", + "requirement": "Die oberste Leitung hat das ISMS in geplanten Abständen zu bewerten (Managementbewertung).", + "link": "{{LINK:R03#ISO-MS-MGMTREVIEW}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-22" + ] + }, + { + "id": "10.1-1", + "policy": "R03", + "control": "10.1", + "kind": "clause", + "title": "Fortlaufende Verbesserung", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 10.1-1", + "impl_anchor": "IMPL ISO-MS-CAPA", + "requirement": "Die Eignung, Angemessenheit und Wirksamkeit des ISMS ist fortlaufend zu verbessern.", + "link": "{{LINK:R03#ISO-MS-CAPA}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-21" + ] + }, + { + "id": "10.2-1", + "policy": "R03", + "control": "10.2", + "kind": "clause", + "title": "Nichtkonformität und Korrekturmaßnahmen", + "type": "MUSS", + "soa_relevant": false, + "applicable": true, + "condition": null, + "req_anchor": "REQ 10.2-1", + "impl_anchor": "IMPL ISO-MS-CAPA", + "requirement": "Bei Nichtkonformitäten sind Korrekturen vorzunehmen und Korrekturmaßnahmen zur Beseitigung der Ursachen zu ergreifen.", + "link": "{{LINK:R03#ISO-MS-CAPA}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-21" + ] + }, + { + "id": "A.5.1-1", + "policy": "L00", + "control": "A.5.1", + "kind": "control", + "title": "Informationssicherheitsrichtlinien", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.1-1", + "impl_anchor": "IMPL ISO-LEITLINIE", + "requirement": "Ein Satz von Informationssicherheitsrichtlinien ist zu definieren, von der Leitung zu genehmigen, zu veröffentlichen, zu kommunizieren und regelmäßig sowie anlassbezogen zu überprüfen.", + "link": "{{LINK:L00#ISO-LEITLINIE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.2-1", + "policy": "R01", + "control": "A.5.2", + "kind": "control", + "title": "Rollen und Verantwortlichkeiten", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.2-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Rollen und Verantwortlichkeiten für die Informationssicherheit sind zu definieren und zuzuweisen.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.3-1", + "policy": "R01", + "control": "A.5.3", + "kind": "control", + "title": "Aufgabentrennung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.3-1", + "impl_anchor": "IMPL 1.2.2", + "requirement": "Widerstreitende Aufgaben und Verantwortungsbereiche sind zu trennen, um unbefugte oder unbeabsichtigte Änderungen und Missbrauch zu reduzieren.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.4-1", + "policy": "R01", + "control": "A.5.4", + "kind": "control", + "title": "Verantwortung der Leitung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.4-1", + "impl_anchor": "IMPL 1.2.1", + "requirement": "Die Leitung hat von allen Beschäftigten die Anwendung der Informationssicherheit gemäß den festgelegten Vorgaben einzufordern.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.5-1", + "policy": "R01", + "control": "A.5.5", + "kind": "control", + "title": "Kontakt mit Behörden", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.5-1", + "impl_anchor": "IMPL ISO-KONTAKTE", + "requirement": "Angemessene Kontakte zu relevanten Behörden sind einzurichten und zu pflegen.", + "link": "{{LINK:R01#ISO-KONTAKTE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.6-1", + "policy": "R01", + "control": "A.5.6", + "kind": "control", + "title": "Kontakt mit speziellen Interessengruppen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.6-1", + "impl_anchor": "IMPL ISO-KONTAKTE", + "requirement": "Angemessene Kontakte zu speziellen Interessengruppen, Fachforen und Sicherheitsverbänden sind zu pflegen.", + "link": "{{LINK:R01#ISO-KONTAKTE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.7-1", + "policy": "R10", + "control": "A.5.7", + "kind": "control", + "title": "Bedrohungsinformationen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.7-1", + "impl_anchor": "IMPL ISO-THREATINTEL", + "requirement": "Informationen über Bedrohungen sind zu sammeln und auszuwerten, um Bedrohungsinformationen (Threat Intelligence) zu erzeugen und zu nutzen.", + "link": "{{LINK:R10#ISO-THREATINTEL}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.8-1", + "policy": "R01", + "control": "A.5.8", + "kind": "control", + "title": "Informationssicherheit im Projektmanagement", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.8-1", + "impl_anchor": "IMPL 1.2.3", + "requirement": "Informationssicherheit ist in das Projektmanagement zu integrieren.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "A.5.9-1", + "policy": "R02", + "control": "A.5.9", + "kind": "control", + "title": "Inventar der Informationen und Assets", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.9-1", + "impl_anchor": "IMPL 1.3.1", + "requirement": "Ein Inventar der Informationen und zugehörigen Assets einschließlich Eigentümer ist zu erstellen und zu pflegen.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.10-1", + "policy": "R02", + "control": "A.5.10", + "kind": "control", + "title": "Zulässige Nutzung von Informationen und Assets", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.10-1", + "impl_anchor": "IMPL 1.3.3", + "requirement": "Regeln zur zulässigen Nutzung und zum Umgang mit Informationen und Assets sind festzulegen, zu dokumentieren und umzusetzen.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.11-1", + "policy": "R11", + "control": "A.5.11", + "kind": "control", + "title": "Rückgabe von Assets", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.11-1", + "impl_anchor": "IMPL 5.3.3", + "requirement": "Beschäftigte und externe Nutzer haben bei Beendigung des Beschäftigungs-/Vertragsverhältnisses alle in ihrem Besitz befindlichen Assets zurückzugeben.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.12-1", + "policy": "R02", + "control": "A.5.12", + "kind": "control", + "title": "Klassifizierung von Informationen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.12-1", + "impl_anchor": "IMPL 1.3.2", + "requirement": "Informationen sind entsprechend ihrem Schutzbedarf (Vertraulichkeit, Integrität, Verfügbarkeit) zu klassifizieren.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.13-1", + "policy": "R02", + "control": "A.5.13", + "kind": "control", + "title": "Kennzeichnung von Informationen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.13-1", + "impl_anchor": "IMPL 1.3.2", + "requirement": "Verfahren zur Kennzeichnung von Informationen gemäß dem Klassifizierungsschema sind zu entwickeln und umzusetzen.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.5.14-1", + "policy": "R09", + "control": "A.5.14", + "kind": "control", + "title": "Informationsübertragung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.14-1", + "impl_anchor": "IMPL 5.1.2", + "requirement": "Regeln, Verfahren und Vereinbarungen zur sicheren Übertragung von Informationen für alle genutzten Übertragungswege sind festzulegen.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.5.15-1", + "policy": "R08", + "control": "A.5.15", + "kind": "control", + "title": "Zugangssteuerung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.15-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Regeln zur Steuerung des physischen und logischen Zugriffs auf Informationen und Assets sind auf Basis der Geschäfts- und Informationssicherheitsanforderungen festzulegen und umzusetzen.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.16-1", + "policy": "R08", + "control": "A.5.16", + "kind": "control", + "title": "Identitätsmanagement", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.16-1", + "impl_anchor": "IMPL 4.1.1", + "requirement": "Der vollständige Lebenszyklus von Identitäten ist zu verwalten.", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.17-1", + "policy": "R08", + "control": "A.5.17", + "kind": "control", + "title": "Authentisierungsinformationen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.17-1", + "impl_anchor": "IMPL 4.1.3", + "requirement": "Die Zuteilung und Verwaltung von Authentisierungsinformationen ist durch einen geeigneten Verwaltungsprozess zu steuern.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.18-1", + "policy": "R08", + "control": "A.5.18", + "kind": "control", + "title": "Zugriffsrechte", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.18-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Zugriffsrechte sind gemäß der Zugriffssteuerungsrichtlinie zuzuteilen, zu überprüfen, zu ändern und zu entziehen.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.5.19-1", + "policy": "R13", + "control": "A.5.19", + "kind": "control", + "title": "Informationssicherheit in Lieferantenbeziehungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.19-1", + "impl_anchor": "IMPL 6.1.1", + "requirement": "Prozesse zur Steuerung der Informationssicherheitsrisiken aus Lieferantenbeziehungen sind festzulegen und umzusetzen.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.20-1", + "policy": "R13", + "control": "A.5.20", + "kind": "control", + "title": "Informationssicherheit in Lieferantenvereinbarungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.20-1", + "impl_anchor": "IMPL 6.1.2", + "requirement": "Relevante Informationssicherheitsanforderungen sind mit jedem Lieferanten zu vereinbaren und vertraglich festzuhalten.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.21-1", + "policy": "R13", + "control": "A.5.21", + "kind": "control", + "title": "Informationssicherheit in der IKT-Lieferkette", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.21-1", + "impl_anchor": "IMPL 6.1.3", + "requirement": "Prozesse zum Umgang mit Informationssicherheitsrisiken in der IKT-Produkt- und Dienstleistungs-Lieferkette sind festzulegen und umzusetzen.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.22-1", + "policy": "R13", + "control": "A.5.22", + "kind": "control", + "title": "Überwachung und Änderung von Lieferantenleistungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.22-1", + "impl_anchor": "IMPL 6.1.1", + "requirement": "Die Informationssicherheit von Lieferantenleistungen ist regelmäßig zu überwachen, zu überprüfen und Änderungen sind zu steuern.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "A.5.23-1", + "policy": "R12", + "control": "A.5.23", + "kind": "control", + "title": "Informationssicherheit bei Cloud-Diensten", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_CLOUD_USED", + "req_anchor": "REQ A.5.23-1", + "impl_anchor": "IMPL 5.3.4", + "requirement": "Prozesse für Beschaffung, Nutzung, Verwaltung und Beendigung von Cloud-Diensten sind entsprechend den Informationssicherheitsanforderungen festzulegen.", + "link": "{{LINK:R12#5.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "A.5.24-1", + "policy": "R04", + "control": "A.5.24", + "kind": "control", + "title": "Incident-Management: Planung und Vorbereitung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.24-1", + "impl_anchor": "IMPL 1.6.1", + "requirement": "Das Management von Informationssicherheitsvorfällen ist zu planen und vorzubereiten (Rollen, Prozesse, Verantwortlichkeiten).", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.25-1", + "policy": "R04", + "control": "A.5.25", + "kind": "control", + "title": "Bewertung und Entscheidung zu Ereignissen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.25-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Informationssicherheitsereignisse sind zu bewerten und es ist zu entscheiden, ob sie als Informationssicherheitsvorfälle einzustufen sind.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.26-1", + "policy": "R04", + "control": "A.5.26", + "kind": "control", + "title": "Reaktion auf Informationssicherheitsvorfälle", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.26-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Auf Informationssicherheitsvorfälle ist gemäß dokumentierten Verfahren zu reagieren.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.27-1", + "policy": "R04", + "control": "A.5.27", + "kind": "control", + "title": "Lernen aus Informationssicherheitsvorfällen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.27-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Aus Informationssicherheitsvorfällen gewonnene Erkenntnisse sind zur Stärkung der Maßnahmen zu nutzen.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.28-1", + "policy": "R04", + "control": "A.5.28", + "kind": "control", + "title": "Sammeln von Beweismaterial", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.28-1", + "impl_anchor": "IMPL 1.6.2", + "requirement": "Verfahren zur Identifizierung, Sammlung, Beschaffung und Aufbewahrung von Beweismaterial zu Vorfällen sind festzulegen und umzusetzen.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.5.29-1", + "policy": "R04", + "control": "A.5.29", + "kind": "control", + "title": "Informationssicherheit während einer Störung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.29-1", + "impl_anchor": "IMPL 1.6.3", + "requirement": "Die Aufrechterhaltung der Informationssicherheit während Störungen ist zu planen und umzusetzen.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "A.5.30-1", + "policy": "R04", + "control": "A.5.30", + "kind": "control", + "title": "IKT-Bereitschaft für Business Continuity", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.30-1", + "impl_anchor": "IMPL 5.2.8", + "requirement": "Die IKT-Bereitschaft ist auf Basis der Business-Continuity-Ziele und -Anforderungen zu planen, umzusetzen und zu testen.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "A.5.31-1", + "policy": "R14", + "control": "A.5.31", + "kind": "control", + "title": "Rechtliche und vertragliche Anforderungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.31-1", + "impl_anchor": "IMPL 7.1.1", + "requirement": "Rechtliche, gesetzliche, regulatorische und vertragliche Anforderungen an die Informationssicherheit sind zu identifizieren, zu dokumentieren und aktuell zu halten.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.32-1", + "policy": "R14", + "control": "A.5.32", + "kind": "control", + "title": "Geistige Eigentumsrechte", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.32-1", + "impl_anchor": "IMPL 7.1.1", + "requirement": "Geeignete Verfahren zum Schutz geistiger Eigentumsrechte sind umzusetzen.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.33-1", + "policy": "R14", + "control": "A.5.33", + "kind": "control", + "title": "Schutz von Aufzeichnungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.33-1", + "impl_anchor": "IMPL 7.1.1", + "requirement": "Aufzeichnungen sind vor Verlust, Zerstörung, Fälschung sowie unbefugtem Zugriff und unbefugter Veröffentlichung zu schützen.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.34-1", + "policy": "R14", + "control": "A.5.34", + "kind": "control", + "title": "Datenschutz und Schutz von PII", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_PERSONAL_DATA", + "req_anchor": "REQ A.5.34-1", + "impl_anchor": "IMPL 7.1.2", + "requirement": "Anforderungen an den Schutz personenbezogener Daten (PII) sind zu identifizieren und gemäß geltenden Vorgaben zu erfüllen.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "A.5.35-1", + "policy": "R03", + "control": "A.5.35", + "kind": "control", + "title": "Unabhängige Überprüfung der Informationssicherheit", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.35-1", + "impl_anchor": "IMPL 1.5.2", + "requirement": "Der Ansatz der Organisation zur Steuerung der Informationssicherheit ist unabhängig und in geplanten Abständen zu überprüfen.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "A.5.36-1", + "policy": "R03", + "control": "A.5.36", + "kind": "control", + "title": "Einhaltung von Richtlinien und Standards", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.36-1", + "impl_anchor": "IMPL 1.5.1", + "requirement": "Die Einhaltung der Informationssicherheitspolitik, themenspezifischer Richtlinien, Regeln und Standards ist regelmäßig zu überprüfen.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "A.5.37-1", + "policy": "R10", + "control": "A.5.37", + "kind": "control", + "title": "Dokumentierte Betriebsabläufe", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.5.37-1", + "impl_anchor": "IMPL ISO-BETRIEBSABLAEUFE", + "requirement": "Betriebsabläufe für informationsverarbeitende Einrichtungen sind zu dokumentieren und den betroffenen Personen bereitzustellen.", + "link": "{{LINK:R10#ISO-BETRIEBSABLAEUFE}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.6.1-1", + "policy": "R05", + "control": "A.6.1", + "kind": "control", + "title": "Überprüfung (Screening)", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.1-1", + "impl_anchor": "IMPL 2.1.1", + "requirement": "Hintergrundüberprüfungen von Bewerbern sind angemessen zu den Geschäftsanforderungen und gesetzeskonform durchzuführen.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.2-1", + "policy": "R05", + "control": "A.6.2", + "kind": "control", + "title": "Arbeitsvertragliche Regelungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.2-1", + "impl_anchor": "IMPL 2.1.2", + "requirement": "Die arbeitsvertraglichen Vereinbarungen legen die Verantwortlichkeiten für die Informationssicherheit fest.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.3-1", + "policy": "R05", + "control": "A.6.3", + "kind": "control", + "title": "Awareness, Ausbildung und Schulung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.3-1", + "impl_anchor": "IMPL 2.1.3", + "requirement": "Beschäftigte erhalten angemessene Awareness, Aus- und Weiterbildung sowie regelmäßige Aktualisierungen der relevanten Richtlinien.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "A.6.4-1", + "policy": "R05", + "control": "A.6.4", + "kind": "control", + "title": "Disziplinarverfahren", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.4-1", + "impl_anchor": "IMPL ISO-DISZIPLIN", + "requirement": "Ein Disziplinarverfahren für Verstöße gegen die Informationssicherheit ist festzulegen und zu kommunizieren.", + "link": "{{LINK:R05#ISO-DISZIPLIN}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.6.5-1", + "policy": "R05", + "control": "A.6.5", + "kind": "control", + "title": "Verantwortlichkeiten nach Beendigung oder Wechsel", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.5-1", + "impl_anchor": "IMPL 2.1.2", + "requirement": "Fortbestehende Informationssicherheitsverantwortlichkeiten nach Beendigung oder Wechsel des Beschäftigungsverhältnisses sind zu definieren und durchzusetzen.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.6-1", + "policy": "R05", + "control": "A.6.6", + "kind": "control", + "title": "Vertraulichkeitsvereinbarungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.6-1", + "impl_anchor": "IMPL 2.1.2", + "requirement": "Vertraulichkeits- bzw. Geheimhaltungsvereinbarungen sind zu identifizieren, zu dokumentieren und regelmäßig zu überprüfen.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "A.6.7-1", + "policy": "R06", + "control": "A.6.7", + "kind": "control", + "title": "Remote-Arbeit", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_MOBILE_WORK", + "req_anchor": "REQ A.6.7-1", + "impl_anchor": "IMPL 2.1.4", + "requirement": "Sicherheitsmaßnahmen für das Arbeiten außerhalb der Räumlichkeiten der Organisation sind umzusetzen.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.6.8-1", + "policy": "R04", + "control": "A.6.8", + "kind": "control", + "title": "Meldung von Informationssicherheitsereignissen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.6.8-1", + "impl_anchor": "IMPL 1.6.1", + "requirement": "Ein Mechanismus zur zeitnahen Meldung beobachteter oder vermuteter Informationssicherheitsereignisse ist bereitzustellen.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "A.7.1-1", + "policy": "R07", + "control": "A.7.1", + "kind": "control", + "title": "Physische Sicherheitsperimeter", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.1-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Sicherheitsperimeter sind zu definieren und zum Schutz von Bereichen mit Informationen und Assets zu nutzen.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.2-1", + "policy": "R07", + "control": "A.7.2", + "kind": "control", + "title": "Physische Zutrittssteuerung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.2-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Sichere Zutrittskontrollen und Zutrittspunkte sind einzurichten, um den Zugang auf Berechtigte zu beschränken.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.3-1", + "policy": "R07", + "control": "A.7.3", + "kind": "control", + "title": "Sicherung von Büros, Räumen und Einrichtungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.3-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Physische Sicherheit für Büros, Räume und Einrichtungen ist zu gestalten und umzusetzen.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.4-1", + "policy": "R07", + "control": "A.7.4", + "kind": "control", + "title": "Physische Überwachung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.4-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Räumlichkeiten sind kontinuierlich auf unbefugten physischen Zugang zu überwachen.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.5-1", + "policy": "R07", + "control": "A.7.5", + "kind": "control", + "title": "Schutz vor physischen und umweltbedingten Bedrohungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.5-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Schutz gegen physische und umweltbedingte Bedrohungen ist zu gestalten und umzusetzen.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.6-1", + "policy": "R07", + "control": "A.7.6", + "kind": "control", + "title": "Arbeiten in Sicherheitsbereichen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.6-1", + "impl_anchor": "IMPL 3.1.1", + "requirement": "Für das Arbeiten in Sicherheitsbereichen sind Maßnahmen festzulegen und umzusetzen.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.7-1", + "policy": "R07", + "control": "A.7.7", + "kind": "control", + "title": "Aufgeräumter Arbeitsplatz und Bildschirm", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.7-1", + "impl_anchor": "IMPL ISO-PHY-CLEARDESK", + "requirement": "Regeln für einen aufgeräumten Arbeitsplatz und gesperrte Bildschirme sind festzulegen und umzusetzen.", + "link": "{{LINK:R07#ISO-PHY-CLEARDESK}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.8-1", + "policy": "R07", + "control": "A.7.8", + "kind": "control", + "title": "Platzierung und Schutz von Betriebsmitteln", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.8-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Betriebsmittel sind sicher zu platzieren und zu schützen.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.9-1", + "policy": "R06", + "control": "A.7.9", + "kind": "control", + "title": "Sicherheit von Assets außerhalb des Geländes", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_MOBILE_DEVICES", + "req_anchor": "REQ A.7.9-1", + "impl_anchor": "IMPL 3.1.4", + "requirement": "Assets, die außerhalb der Räumlichkeiten genutzt werden, sind zu schützen.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.7.10-1", + "policy": "R06", + "control": "A.7.10", + "kind": "control", + "title": "Speichermedien", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.10-1", + "impl_anchor": "IMPL 3.1.4", + "requirement": "Speichermedien sind über ihren gesamten Lebenszyklus (Erwerb, Nutzung, Transport, Entsorgung) entsprechend dem Klassifizierungsschema zu schützen.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.7.11-1", + "policy": "R07", + "control": "A.7.11", + "kind": "control", + "title": "Versorgungseinrichtungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.11-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Einrichtungen sind vor Ausfällen und Störungen der Versorgung (z. B. Strom, Klima) zu schützen.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.12-1", + "policy": "R07", + "control": "A.7.12", + "kind": "control", + "title": "Verkabelungssicherheit", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.12-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Verkabelung für Strom und Daten ist vor Abhören, Störung und Beschädigung zu schützen.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "A.7.13-1", + "policy": "R07", + "control": "A.7.13", + "kind": "control", + "title": "Wartung von Betriebsmitteln", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.13-1", + "impl_anchor": "IMPL ISO-PHY-UMWELT", + "requirement": "Betriebsmittel sind ordnungsgemäß zu warten, um Verfügbarkeit und Integrität sicherzustellen.", + "link": "{{LINK:R07#ISO-PHY-UMWELT}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.7.14-1", + "policy": "R11", + "control": "A.7.14", + "kind": "control", + "title": "Sichere Entsorgung oder Wiederverwendung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.7.14-1", + "impl_anchor": "IMPL 5.3.3", + "requirement": "Betriebsmittel mit Speichermedien sind vor Entsorgung oder Wiederverwendung sicher zu bereinigen (Datenlöschung).", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.8.1-1", + "policy": "R06", + "control": "A.8.1", + "kind": "control", + "title": "Endgeräte der Benutzer", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.1-1", + "impl_anchor": "IMPL 3.1.4", + "requirement": "Informationen, die auf Endgeräten der Benutzer gespeichert, verarbeitet oder darüber zugänglich sind, sind zu schützen.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.2-1", + "policy": "R08", + "control": "A.8.2", + "kind": "control", + "title": "Privilegierte Zugriffsrechte", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.2-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Die Zuteilung und Nutzung privilegierter Zugriffsrechte ist einzuschränken und eng zu steuern.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.3-1", + "policy": "R08", + "control": "A.8.3", + "kind": "control", + "title": "Einschränkung des Informationszugriffs", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.3-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Der Zugriff auf Informationen und Anwendungsfunktionen ist gemäß der Zugriffssteuerungsrichtlinie einzuschränken.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.4-1", + "policy": "R11", + "control": "A.8.4", + "kind": "control", + "title": "Zugriff auf Quellcode", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.4-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Der Lese- und Schreibzugriff auf Quellcode, Entwicklungswerkzeuge und Softwarebibliotheken ist angemessen zu steuern.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.5-1", + "policy": "R08", + "control": "A.8.5", + "kind": "control", + "title": "Sichere Authentisierung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.5-1", + "impl_anchor": "IMPL 4.1.2", + "requirement": "Sichere Authentisierungstechnologien und -verfahren sind auf Basis der Zugriffsbeschränkungen und der Zugriffssteuerungsrichtlinie einzusetzen.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.6-1", + "policy": "R10", + "control": "A.8.6", + "kind": "control", + "title": "Kapazitätssteuerung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.6-1", + "impl_anchor": "IMPL ISO-KAPAZITAET", + "requirement": "Ressourcen sind zu überwachen und die Kapazität ist an den aktuellen und erwarteten Bedarf anzupassen.", + "link": "{{LINK:R10#ISO-KAPAZITAET}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.7-1", + "policy": "R10", + "control": "A.8.7", + "kind": "control", + "title": "Schutz vor Malware", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.7-1", + "impl_anchor": "IMPL 5.2.3", + "requirement": "Schutz vor Schadsoftware ist umzusetzen und durch angemessene Awareness der Benutzer zu unterstützen.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.8-1", + "policy": "R10", + "control": "A.8.8", + "kind": "control", + "title": "Management technischer Schwachstellen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.8-1", + "impl_anchor": "IMPL 5.2.5", + "requirement": "Informationen über technische Schwachstellen sind zu beschaffen, die Betroffenheit zu bewerten und geeignete Maßnahmen zu ergreifen.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-06" + ] + }, + { + "id": "A.8.9-1", + "policy": "R10", + "control": "A.8.9", + "kind": "control", + "title": "Konfigurationsmanagement", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.9-1", + "impl_anchor": "IMPL 5.2.1", + "requirement": "Konfigurationen von Hardware, Software, Diensten und Netzen sind festzulegen, zu dokumentieren, umzusetzen, zu überwachen und zu überprüfen.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.8.10-1", + "policy": "R11", + "control": "A.8.10", + "kind": "control", + "title": "Löschung von Informationen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.10-1", + "impl_anchor": "IMPL 5.3.3", + "requirement": "In Systemen und auf Medien gespeicherte Informationen sind zu löschen, sobald sie nicht mehr benötigt werden.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "A.8.11-1", + "policy": "R02", + "control": "A.8.11", + "kind": "control", + "title": "Datenmaskierung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_PERSONAL_DATA", + "req_anchor": "REQ A.8.11-1", + "impl_anchor": "IMPL ISO-MASKIERUNG", + "requirement": "Datenmaskierung ist gemäß den Zugriffs- und Datenschutzanforderungen einzusetzen.", + "link": "{{LINK:R02#ISO-MASKIERUNG}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.12-1", + "policy": "R10", + "control": "A.8.12", + "kind": "control", + "title": "Verhinderung von Datenlecks", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.12-1", + "impl_anchor": "IMPL ISO-DLP", + "requirement": "Maßnahmen zur Verhinderung von Datenlecks sind auf Systeme, Netze und Geräte anzuwenden, die sensible Informationen verarbeiten.", + "link": "{{LINK:R10#ISO-DLP}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.13-1", + "policy": "R10", + "control": "A.8.13", + "kind": "control", + "title": "Informationssicherung (Backup)", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.13-1", + "impl_anchor": "IMPL 5.2.9", + "requirement": "Sicherungskopien von Informationen, Software und Systemen sind gemäß Sicherungskonzept zu erstellen und regelmäßig zu testen.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "A.8.14-1", + "policy": "R04", + "control": "A.8.14", + "kind": "control", + "title": "Redundanz der Verarbeitungseinrichtungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.14-1", + "impl_anchor": "IMPL 5.2.8", + "requirement": "Informationsverarbeitende Einrichtungen sind mit ausreichender Redundanz auszulegen, um die Verfügbarkeitsanforderungen zu erfüllen.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "A.8.15-1", + "policy": "R10", + "control": "A.8.15", + "kind": "control", + "title": "Protokollierung (Logging)", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.15-1", + "impl_anchor": "IMPL 5.2.4", + "requirement": "Protokolle über Aktivitäten, Ausnahmen, Fehler und Ereignisse sind zu erzeugen, zu speichern, zu schützen und auszuwerten.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "A.8.16-1", + "policy": "R10", + "control": "A.8.16", + "kind": "control", + "title": "Überwachungsaktivitäten", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.16-1", + "impl_anchor": "IMPL 5.2.4", + "requirement": "Netze, Systeme und Anwendungen sind auf anomales Verhalten zu überwachen und mögliche Vorfälle zu bewerten.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "A.8.17-1", + "policy": "R10", + "control": "A.8.17", + "kind": "control", + "title": "Uhrzeitsynchronisation", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.17-1", + "impl_anchor": "IMPL ISO-ZEITSYNC", + "requirement": "Die Uhren der Systeme sind auf zugelassene Zeitquellen zu synchronisieren.", + "link": "{{LINK:R10#ISO-ZEITSYNC}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "A.8.18-1", + "policy": "R08", + "control": "A.8.18", + "kind": "control", + "title": "Nutzung privilegierter Hilfsprogramme", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.18-1", + "impl_anchor": "IMPL 4.2.1", + "requirement": "Die Nutzung von Hilfsprogrammen, die System- und Anwendungskontrollen umgehen können, ist einzuschränken und streng zu steuern.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "A.8.19-1", + "policy": "R02", + "control": "A.8.19", + "kind": "control", + "title": "Softwareinstallation auf Produktivsystemen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.19-1", + "impl_anchor": "IMPL 1.3.4", + "requirement": "Verfahren und Maßnahmen zur sicheren Verwaltung der Softwareinstallation auf Produktivsystemen sind umzusetzen.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.8.20-1", + "policy": "R10", + "control": "A.8.20", + "kind": "control", + "title": "Netzwerksicherheit", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.20-1", + "impl_anchor": "IMPL 5.2.7", + "requirement": "Netze und Netzwerkgeräte sind zu sichern, zu verwalten und zu steuern, um Informationen zu schützen.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.21-1", + "policy": "R11", + "control": "A.8.21", + "kind": "control", + "title": "Sicherheit von Netzwerkdiensten", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.21-1", + "impl_anchor": "IMPL 5.3.2", + "requirement": "Sicherheitsmechanismen, Dienstgüten und Anforderungen an Netzwerkdienste sind zu identifizieren, umzusetzen und zu überwachen.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.22-1", + "policy": "R10", + "control": "A.8.22", + "kind": "control", + "title": "Netzwerksegmentierung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.22-1", + "impl_anchor": "IMPL 5.2.7", + "requirement": "Gruppen von Informationsdiensten, Nutzern und Systemen sind in Netzen zu segmentieren.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.23-1", + "policy": "R10", + "control": "A.8.23", + "kind": "control", + "title": "Web-Filterung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.23-1", + "impl_anchor": "IMPL 5.2.3", + "requirement": "Der Zugriff auf externe Webseiten ist zu steuern, um die Exposition gegenüber schädlichen Inhalten zu reduzieren.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "A.8.24-1", + "policy": "R09", + "control": "A.8.24", + "kind": "control", + "title": "Nutzung von Kryptographie", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.24-1", + "impl_anchor": "IMPL 5.1.1", + "requirement": "Regeln für die wirksame Nutzung von Kryptographie einschließlich Schlüsselverwaltung sind festzulegen und umzusetzen.", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "A.8.25-1", + "policy": "R11", + "control": "A.8.25", + "kind": "control", + "title": "Sicherer Entwicklungslebenszyklus", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.25-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Regeln für einen sicheren Entwicklungslebenszyklus von Software und Systemen sind festzulegen und anzuwenden.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.26-1", + "policy": "R11", + "control": "A.8.26", + "kind": "control", + "title": "Sicherheitsanforderungen an Anwendungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.26-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Informationssicherheitsanforderungen sind bei Entwicklung oder Beschaffung von Anwendungen zu ermitteln, zu spezifizieren und zu berücksichtigen.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.27-1", + "policy": "R11", + "control": "A.8.27", + "kind": "control", + "title": "Sichere Systemarchitektur und -prinzipien", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.27-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Grundsätze für die Entwicklung sicherer Systeme sind festzulegen, zu dokumentieren und anzuwenden.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.28-1", + "policy": "R11", + "control": "A.8.28", + "kind": "control", + "title": "Sichere Programmierung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.28-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Grundsätze für sichere Programmierung sind auf die Softwareentwicklung anzuwenden.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.29-1", + "policy": "R11", + "control": "A.8.29", + "kind": "control", + "title": "Sicherheitstests in Entwicklung und Abnahme", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.29-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Sicherheitstests sind in den Entwicklungs- und Abnahmeprozess zu integrieren.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.30-1", + "policy": "R11", + "control": "A.8.30", + "kind": "control", + "title": "Ausgelagerte Entwicklung", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.30-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Ausgelagerte Systementwicklung ist zu steuern, zu überwachen und zu überprüfen.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.31-1", + "policy": "R10", + "control": "A.8.31", + "kind": "control", + "title": "Trennung von Entwicklungs-, Test- und Produktionsumgebungen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.31-1", + "impl_anchor": "IMPL 5.2.2", + "requirement": "Entwicklungs-, Test- und Produktionsumgebungen sind zu trennen und zu schützen.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.32-1", + "policy": "R10", + "control": "A.8.32", + "kind": "control", + "title": "Änderungsmanagement", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.32-1", + "impl_anchor": "IMPL 5.2.1", + "requirement": "Änderungen an informationsverarbeitenden Einrichtungen und Systemen sind einem Änderungsmanagement zu unterziehen.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "A.8.33-1", + "policy": "R11", + "control": "A.8.33", + "kind": "control", + "title": "Testinformationen", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": "FLAG_DEV_INHOUSE", + "req_anchor": "REQ A.8.33-1", + "impl_anchor": "IMPL 5.3.1", + "requirement": "Testinformationen sind sorgfältig auszuwählen, zu schützen und zu verwalten.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "A.8.34-1", + "policy": "R10", + "control": "A.8.34", + "kind": "control", + "title": "Schutz von Systemen bei Audit-Tests", + "type": "MUSS", + "soa_relevant": true, + "applicable": true, + "condition": null, + "req_anchor": "REQ A.8.34-1", + "impl_anchor": "IMPL 5.2.6", + "requirement": "Audit-Tests und ähnliche Prüftätigkeiten an Produktivsystemen sind zu planen und zu vereinbaren, um Beeinträchtigungen zu vermeiden.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + } + ] +} diff --git a/seed/isms-vorlagenpaket-v2/mapping.json b/seed/isms-vorlagenpaket-v2/mapping.json new file mode 100644 index 0000000..2776593 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/mapping.json @@ -0,0 +1,5351 @@ +{ + "meta": { + "paket": "ISMS-Vorlagenpaket v2", + "standard": "VDA ISA 2027 (Information Security)", + "hinweis": "Anforderungen 1:1 aus ISA; Umsetzung gebuendelt je Control. is_isa=false = kundenspezifische Ergaenzung (z.B. KI).", + "isa_quelldubletten": [ + { + "control": "1.6.3", + "ebene": "high", + "doppelte_quellzeilen": 3, + "abgedeckt_durch": [ + "1.6.3-H1", + "1.6.3-H2", + "1.6.3-H5" + ], + "hinweis": "ISA wiederholt Krisenszenario-/Ressourcen-/Test-Zeilen mit/ohne Zusatz \"The following aspects are considered\"." + }, + { + "control": "5.2.9", + "ebene": "high", + "doppelte_quellzeilen": 1, + "abgedeckt_durch": [ + "5.2.9-H1" + ], + "hinweis": "ISA-Zeile \"Backup and recovery concepts exist\" ist redundant zum Must-Konzept und zu H1." + } + ], + "coverage": "316 eindeutige ISA-Zeilen; 4 Quelldubletten konsolidiert -> 312 eindeutige Anforderungen (100% inhaltliche Abdeckung). Plus 4 kundenspezifische KI-Anforderungen.", + "version": "2.1" + }, + "anforderungen": [ + { + "id": "1.1.1-M1", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M1", + "impl_anchor": "REQ 1.1.1-M1", + "condition": null, + "requirement": "Die Anforderungen der Informationssicherheit sind bestimmt, dokumentiert und an den Zielen der Organisation ausgerichtet.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M2", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M2", + "impl_anchor": "REQ 1.1.1-M2", + "condition": null, + "requirement": "Eine Leitlinie existiert und ist durch die Leitung der Organisation genehmigt.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M3", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M3", + "impl_anchor": "REQ 1.1.1-M3", + "condition": null, + "requirement": "Die Leitlinie benennt Ziele und die Bedeutung der Informationssicherheit innerhalb der Organisation.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M4", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M4", + "impl_anchor": "REQ 1.1.1-M4", + "condition": null, + "requirement": "Die Leitlinien werden den Beschäftigten in geeigneter Form zur Verfügung gestellt (z. B. Intranet).", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-M5", + "policy": "L00", + "control": "1.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.1.1-M5", + "impl_anchor": "REQ 1.1.1-M5", + "condition": null, + "requirement": "Beschäftigte und externe Geschäftspartner werden über für sie relevante Änderungen informiert.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S1", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S1", + "impl_anchor": "REQ 1.1.1-S1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Informationssicherheitsanforderungen basieren auf der Strategie der Organisation; Gesetze und Verträge werden in der Leitlinie berücksichtigt.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S2", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S2", + "impl_anchor": "REQ 1.1.1-S2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Leitlinie benennt Konsequenzen bei Nichteinhaltung.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S3", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S3", + "impl_anchor": "REQ 1.1.1-S3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Weitere relevante Sicherheitsrichtlinien sind etabliert.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.1.1-S4", + "policy": "L00", + "control": "1.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.1.1-S4", + "impl_anchor": "REQ 1.1.1-S4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Regelmäßige Überprüfung und ggf. Überarbeitung der Richtlinien sind etabliert.", + "link": "{{LINK:L00#1.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M1", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M1", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "Der Geltungsbereich des ISMS (die durch das ISMS gesteuerte Organisation) ist definiert.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M2", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M2", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "Die Anforderungen der Organisation an das ISMS sind bestimmt.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M3", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M3", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "Die Organisationsleitung hat das ISMS beauftragt und genehmigt.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M4", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M4", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "Das ISMS stellt der Organisationsleitung geeignete Mittel zur Überwachung und Steuerung bereit (z. B. Managementbewertung).", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M5", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M5", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "Die anwendbaren Controls sind bestimmt (z. B. ISO-27001-Anwendbarkeitserklärung oder ausgefüllter ISA-Katalog).", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.1-M6", + "policy": "R01", + "control": "1.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.1-M6", + "impl_anchor": "IMPL 1.2.1", + "condition": null, + "requirement": "Die Wirksamkeit des ISMS wird regelmäßig durch die Leitung überprüft.", + "link": "{{LINK:R01#1.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M1", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M1", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "Verantwortlichkeiten für Informationssicherheit sind definiert, dokumentiert und zugewiesen.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M2", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M2", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "Die verantwortlichen Beschäftigten sind definiert, qualifiziert und für ihre Aufgabe befähigt.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M3", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M3", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "Die erforderlichen Ressourcen stehen zur Verfügung.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-M4", + "policy": "R01", + "control": "1.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.2-M4", + "impl_anchor": "IMPL 1.2.2", + "condition": null, + "requirement": "Die Ansprechpartner sind innerhalb der Organisation und relevanten Geschäftspartnern bekannt.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-S1", + "policy": "R01", + "control": "1.2.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.2-S1", + "impl_anchor": "IMPL 1.2.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Es besteht eine Definition und Dokumentation einer angemessenen Informationssicherheitsstruktur innerhalb der Organisation.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-S2", + "policy": "R01", + "control": "1.2.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.2-S2", + "impl_anchor": "IMPL 1.2.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Sicherheitsrelevante Rollen, die nicht Teil des ISMS, aber für die Informationssicherheit relevant sind, werden berücksichtigt.", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.2-H1", + "policy": "R01", + "control": "1.2.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.2.2-H1", + "impl_anchor": "IMPL 1.2.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Eine angemessene organisatorische Trennung von Verantwortlichkeiten ist etabliert, um Interessenkonflikte zu vermeiden (Funktionstrennung). (C, I, A)", + "link": "{{LINK:R01#1.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.2.3-M1", + "policy": "R01", + "control": "1.2.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.2.3-M1", + "impl_anchor": "IMPL 1.2.3", + "condition": null, + "requirement": "Projekte werden unter Berücksichtigung der Informationssicherheitsanforderungen klassifiziert.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-S1", + "policy": "R01", + "control": "1.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.3-S1", + "impl_anchor": "IMPL 1.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Verfahren und Kriterien für die Klassifizierung von Projekten sind dokumentiert.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-S2", + "policy": "R01", + "control": "1.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.3-S2", + "impl_anchor": "IMPL 1.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "In einer frühen Projektphase wird eine Risikobewertung nach dem definierten Verfahren durchgeführt und bei Projektänderungen wiederholt.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-S3", + "policy": "R01", + "control": "1.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.2.3-S3", + "impl_anchor": "IMPL 1.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Für identifizierte Informationssicherheitsrisiken werden Maßnahmen abgeleitet und im Projekt berücksichtigt.", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.2.3-H1", + "policy": "R01", + "control": "1.2.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.2.3-H1", + "impl_anchor": "IMPL 1.2.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die abgeleiteten Maßnahmen werden während des Projekts regelmäßig überprüft und bei Änderungen der Bewertungskriterien neu bewertet. (C, I, A)", + "link": "{{LINK:R01#1.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-19" + ] + }, + { + "id": "1.3.1-M1", + "policy": "R02", + "control": "1.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.1-M1", + "impl_anchor": "IMPL 1.3.1", + "condition": null, + "requirement": "Informationswerte und weitere sicherheitsrelevante Assets der Organisation sind identifiziert und erfasst.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.1-M2", + "policy": "R02", + "control": "1.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.1-M2", + "impl_anchor": "IMPL 1.3.1", + "condition": null, + "requirement": "Die unterstützenden Assets, die die Informationswerte verarbeiten, sind identifiziert und erfasst.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.1-S1", + "policy": "R02", + "control": "1.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.1-S1", + "impl_anchor": "IMPL 1.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Katalog der relevanten Informationswerte existiert; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R02#1.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.2-M1", + "policy": "R02", + "control": "1.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.2-M1", + "impl_anchor": "IMPL 1.3.2", + "condition": null, + "requirement": "Ein konsistentes Schema zur Klassifizierung von Informationswerten hinsichtlich des Schutzziels Vertraulichkeit ist vorhanden.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.2-M2", + "policy": "R02", + "control": "1.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.2-M2", + "impl_anchor": "IMPL 1.3.2", + "condition": null, + "requirement": "Die Bewertung der identifizierten Informationswerte erfolgt nach den definierten Kriterien und wird dem Klassifizierungsschema zugeordnet.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.2-M3", + "policy": "R02", + "control": "1.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.2-M3", + "impl_anchor": "IMPL 1.3.2", + "condition": null, + "requirement": "Vorgaben zur Handhabung unterstützender Assets (z. B. Kennzeichnung, Nutzung, Transport, Speicherung, Rückgabe, Löschung/Vernichtung) abhängig von der Klassifizierung sind vorhanden und umgesetzt.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.2-S1", + "policy": "R02", + "control": "1.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.2-S1", + "impl_anchor": "IMPL 1.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Schutzziele Integrität und Verfügbarkeit werden berücksichtigt.", + "link": "{{LINK:R02#1.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-08" + ] + }, + { + "id": "1.3.3-M1", + "policy": "R02", + "control": "1.3.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.3-M1", + "impl_anchor": "IMPL 1.3.3", + "condition": null, + "requirement": "Externe IT-Dienste werden nicht ohne ausdrückliche Bewertung und Umsetzung der Informationssicherheitsanforderungen genutzt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-M2", + "policy": "R02", + "control": "1.3.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.3-M2", + "impl_anchor": "IMPL 1.3.3", + "condition": null, + "requirement": "Die externen IT-Dienste sind mit dem Schutzbedarf der verarbeiteten Informationswerte abgestimmt.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S1", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S1", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Anforderungen an Beschaffung, Inbetriebnahme und Freigabe im Zusammenhang mit der Nutzung externer IT-Dienste sind bestimmt und erfüllt.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S2", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S2", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Verfahren zur Freigabe unter Berücksichtigung des Schutzbedarfs ist etabliert.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S3", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S3", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Externe IT-Dienste und ihre Freigabe sind dokumentiert.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.3-S4", + "policy": "R02", + "control": "1.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.3-S4", + "impl_anchor": "IMPL 1.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Es wird regelmäßig überprüft, dass nur freigegebene externe IT-Dienste genutzt werden.", + "link": "{{LINK:R02#1.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-M1", + "policy": "R02", + "control": "1.3.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.4-M1", + "impl_anchor": "IMPL 1.3.4", + "condition": null, + "requirement": "Software wird vor Installation oder Nutzung freigegeben; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-M2", + "policy": "R02", + "control": "1.3.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.3.4-M2", + "impl_anchor": "IMPL 1.3.4", + "condition": null, + "requirement": "Die Softwarefreigabe gilt auch für Spezialsoftware wie Wartungswerkzeuge.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S1", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S1", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die zu verwaltenden Softwarearten (Firmware, Betriebssysteme, Anwendungen, Bibliotheken, Gerätetreiber) sind bestimmt.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S2", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S2", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Repositorys der verwalteten Software existieren.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S3", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S3", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Software-Repositorys sind gegen unbefugte Manipulation geschützt.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S4", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S4", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Freigabe von Software wird regelmäßig überprüft.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-S5", + "policy": "R02", + "control": "1.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.3.4-S5", + "impl_anchor": "IMPL 1.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Softwareversionen und Patch-Stände sind bekannt.", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.3.4-V1", + "policy": "R02", + "control": "1.3.4", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.3.4-V1", + "impl_anchor": "IMPL 1.3.4-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Zusätzliche Anforderungen an die Softwarenutzung (z. B. Kontroll-/Überwachungsbedarf der Nutzung) sind, sofern vorhanden, bestimmt. (C, I, A)", + "link": "{{LINK:R02#1.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-M1", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M1", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Risikobewertungen werden regelmäßig und anlassbezogen durchgeführt.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-M2", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M2", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Informationssicherheitsrisiken werden angemessen bewertet (z. B. Eintrittswahrscheinlichkeit und mögliches Schadensausmaß).", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-M3", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M3", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Informationssicherheitsrisiken werden dokumentiert.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-M4", + "policy": "R03", + "control": "1.4.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.4.1-M4", + "impl_anchor": "IMPL 1.4.1", + "condition": null, + "requirement": "Jedem Informationssicherheitsrisiko ist ein Verantwortlicher (Risk Owner) zugeordnet, der für Bewertung und Behandlung verantwortlich ist.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-S1", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S1", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Verfahren zur Identifikation, Bewertung und Behandlung von Sicherheitsrisiken ist vorhanden.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-09" + ] + }, + { + "id": "1.4.1-S2", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S2", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Kriterien für Bewertung und Behandlung von Sicherheitsrisiken existieren.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-S3", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S3", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Maßnahmen zur Risikobehandlung und ihre Verantwortlichen sind festgelegt und dokumentiert; ein Maßnahmenplan bzw. eine Umsetzungsübersicht wird nachverfolgt.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.4.1-S4", + "policy": "R03", + "control": "1.4.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.4.1-S4", + "impl_anchor": "IMPL 1.4.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Bei Änderungen des Umfelds (z. B. Organisationsstruktur, Standort, Regularien) erfolgt zeitnah eine Neubewertung.", + "link": "{{LINK:R03#1.4.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.5.1-M1", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M1", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Die Einhaltung der Richtlinien wird organisationsweit überprüft.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M2", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M2", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Informationssicherheitsrichtlinien und -verfahren werden regelmäßig überprüft.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M3", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M3", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M4", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M4", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Die Einhaltung von Informationssicherheitsanforderungen (z. B. technische Vorgaben) wird regelmäßig überprüft.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-M5", + "policy": "R03", + "control": "1.5.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.1-M5", + "impl_anchor": "IMPL 1.5.1", + "condition": null, + "requirement": "Die Ergebnisse der durchgeführten Überprüfungen werden aufgezeichnet und aufbewahrt.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.1-S1", + "policy": "R03", + "control": "1.5.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.5.1-S1", + "impl_anchor": "IMPL 1.5.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Plan für Inhalt und Rahmenbedingungen (Zeitplan, Umfang, Controls) der durchzuführenden Überprüfungen liegt vor.", + "link": "{{LINK:R03#1.5.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.2-M1", + "policy": "R03", + "control": "1.5.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.2-M1", + "impl_anchor": "IMPL 1.5.2", + "condition": null, + "requirement": "Informationssicherheitsüberprüfungen werden durch eine unabhängige und kompetente Stelle regelmäßig und nach grundlegenden Änderungen durchgeführt.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.2-M2", + "policy": "R03", + "control": "1.5.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.5.2-M2", + "impl_anchor": "IMPL 1.5.2", + "condition": null, + "requirement": "Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.5.2-S1", + "policy": "R03", + "control": "1.5.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.5.2-S1", + "impl_anchor": "IMPL 1.5.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Ergebnisse durchgeführter Überprüfungen werden dokumentiert und der Organisationsleitung berichtet.", + "link": "{{LINK:R03#1.5.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-15" + ] + }, + { + "id": "1.6.1-M1", + "policy": "R04", + "control": "1.6.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.1-M1", + "impl_anchor": "IMPL 1.6.1", + "condition": null, + "requirement": "Eine Definition für ein meldepflichtiges Sicherheitsereignis oder eine Beobachtung existiert und ist Beschäftigten und relevanten Stakeholdern bekannt.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.1-M2", + "policy": "R04", + "control": "1.6.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.1-M2", + "impl_anchor": "IMPL 1.6.1", + "condition": null, + "requirement": "Angemessene, risikoorientierte Mechanismen zur Meldung von Sicherheitsereignissen sind definiert, umgesetzt und allen relevanten Meldenden bekannt.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.1-M3", + "policy": "R04", + "control": "1.6.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.1-M3", + "impl_anchor": "IMPL 1.6.1", + "condition": null, + "requirement": "Angemessene Kanäle zur Kommunikation mit Meldenden existieren.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S1", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S1", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine gemeinsame Anlaufstelle für die Ereignismeldung existiert.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S2", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S2", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Verschiedene Meldekanäle je nach wahrgenommener Schwere (Echtzeit für gravierende Ereignisse/Notfälle sowie asynchrone Mechanismen wie Tickets oder E-Mail) sind verfügbar.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S3", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S3", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Beschäftigte sind verpflichtet und geschult, relevante Ereignisse zu melden.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S4", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S4", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Sicherheitsereignisse können auch durch Externe gemeldet werden; die einschlägigen Aspekte werden berücksichtigt.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S5", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S5", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Der Mechanismus und die Information, wie Vorfälle gemeldet werden, sind für alle relevanten Meldenden zugänglich.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-S6", + "policy": "R04", + "control": "1.6.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.1-S6", + "impl_anchor": "IMPL 1.6.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Rückmeldeverfahren an die Meldenden ist etabliert.", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.1-V1", + "policy": "R04", + "control": "1.6.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.1-V1", + "impl_anchor": "IMPL 1.6.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Tests und Übungen der Ereignis- und Beobachtungsmeldung werden regelmäßig durchgeführt. (C, I, A)", + "link": "{{LINK:R04#1.6.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-M1", + "policy": "R04", + "control": "1.6.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.2-M1", + "impl_anchor": "IMPL 1.6.2", + "condition": null, + "requirement": "Gemeldete Ereignisse werden ohne unangemessene Verzögerung bearbeitet.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-M2", + "policy": "R04", + "control": "1.6.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.2-M2", + "impl_anchor": "IMPL 1.6.2", + "condition": null, + "requirement": "Eine angemessene Reaktion auf gemeldete Sicherheitsereignisse ist sichergestellt.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-M3", + "policy": "R04", + "control": "1.6.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.2-M3", + "impl_anchor": "IMPL 1.6.2", + "condition": null, + "requirement": "Lessons Learned fließen in die kontinuierliche Verbesserung ein.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-S1", + "policy": "R04", + "control": "1.6.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.2-S1", + "impl_anchor": "IMPL 1.6.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Gemeldete Ereignisse werden bei der Bearbeitung kategorisiert (z. B. Personal, physisch, Cyber), qualifiziert (z. B. nicht sicherheitsrelevant, Beobachtung, Verbesserungsvorschlag, Schwachstelle, Vorfall) und priorisiert (z. B. gering, mittel, schwer, kritisch).", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-S2", + "policy": "R04", + "control": "1.6.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.2-S2", + "impl_anchor": "IMPL 1.6.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Verantwortlichkeiten für die Behandlung von Ereignissen je Kategorie sind definiert und zugewiesen.", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-01" + ] + }, + { + "id": "1.6.2-S3", + "policy": "R04", + "control": "1.6.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.2-S3", + "impl_anchor": "IMPL 1.6.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine Strategie zur Meldung potenziell strafrechtlich relevanter Aspekte an zuständige Behörden, sofern erforderlich, existiert. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H1", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H1", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Maximale Reaktionszeiten je Klasse, Kategorie und Schwere sind definiert. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H2", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H2", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Nicht prioritätsgerecht bearbeitete Ereignisse werden eskaliert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H3", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H3", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Gesetzliche, regulatorische und vertragliche Meldepflichten sowie zugehörige Kontaktinformationen sind bekannt. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H4", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H4", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Eine Kommunikationsstrategie für sicherheitsrelevante Ereignisse existiert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-H5", + "policy": "R04", + "control": "1.6.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-H5", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Verfahren zur Reaktion auf Sicherheitsvorfälle bei Lieferanten sind etabliert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.2-V1", + "policy": "R04", + "control": "1.6.2", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.2-V1", + "impl_anchor": "IMPL 1.6.2-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Die Behandlung von Ereignissen unterschiedlicher Kategorien und Prioritäten wird regelmäßig getestet; die einschlägigen Aspekte werden berücksichtigt. (A)", + "link": "{{LINK:R04#1.6.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-M1", + "policy": "R04", + "control": "1.6.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.3-M1", + "impl_anchor": "IMPL 1.6.3", + "condition": null, + "requirement": "Ein angemessener Plan zur Reaktion auf und Bewältigung von Krisensituationen existiert und die erforderlichen Ressourcen sind verfügbar.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "1.6.3-M2", + "policy": "R04", + "control": "1.6.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.3-M2", + "impl_anchor": "IMPL 1.6.3", + "condition": null, + "requirement": "Verantwortlichkeiten und Befugnisse für das Krisenmanagement sind definiert, dokumentiert und zugewiesen.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-M3", + "policy": "R04", + "control": "1.6.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 1.6.3-M3", + "impl_anchor": "IMPL 1.6.3", + "condition": null, + "requirement": "Die verantwortlichen Beschäftigten sind definiert und für ihre Aufgabe qualifiziert.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S1", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S1", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Methoden zur Erkennung von Krisensituationen sind etabliert; allgemeine Anzeichen und spezifische vorhersehbare Krisen sind identifiziert.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "1.6.3-S2", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S2", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Verfahren zur Auslösung und/oder Eskalation des Krisenmanagements ist vorhanden.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S3", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S3", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Strategische Ziele und ihre Priorität in Krisensituationen sind definiert und relevantem Personal bekannt.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S4", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S4", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Krisenstab ist definiert und genehmigt.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S5", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S5", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Krisenrichtlinien und -verfahren sind definiert und genehmigt.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-S6", + "policy": "R04", + "control": "1.6.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 1.6.3-S6", + "impl_anchor": "IMPL 1.6.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Krisenplanung wird regelmäßig überprüft und aktualisiert.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H1", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H1", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Relevante unterschiedliche potenzielle Krisenszenarien sind identifiziert.", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H2", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H2", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Notwendige Ressourcen und Informationen zur Krisenbewältigung (z. B. Kommunikationsinfrastruktur, Verfügbarkeit von Kontakt- und Risikoinformationen) sind identifiziert; angemessene Maßnahmen zur Sicherstellung der Verfügbarkeit bzw. Ausfallplanung sind vorhanden. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H3", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H3", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Eine Kommunikationsstrategie für Krisensituationen existiert. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H4", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H4", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Effizienz, Durchführbarkeit und Angemessenheit der Krisenplanung werden regelmäßig bewertet. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-H5", + "policy": "R04", + "control": "1.6.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-H5", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Stichprobenbasierte Tests der Krisenplanung werden durchgeführt (z. B. Simulation, Tabletop-Übungen mit Schlüsselpersonal). (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "1.6.3-V1", + "policy": "R04", + "control": "1.6.3", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 1.6.3-V1", + "impl_anchor": "IMPL 1.6.3-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Krisenübungen und Simulationen unter Einbindung aller relevanten Personen, einschließlich Entscheidungsträger, werden regelmäßig durchgeführt. (A)", + "link": "{{LINK:R04#1.6.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.1-M1", + "policy": "R05", + "control": "2.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.1-M1", + "impl_anchor": "IMPL 2.1.1", + "condition": null, + "requirement": "Sensible Arbeitsbereiche und Tätigkeiten sind bestimmt.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-M2", + "policy": "R05", + "control": "2.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.1-M2", + "impl_anchor": "IMPL 2.1.1", + "condition": null, + "requirement": "Die Anforderungen an Beschäftigte hinsichtlich ihrer Stellenprofile sind bestimmt und erfüllt.", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-M3", + "policy": "R05", + "control": "2.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.1-M3", + "impl_anchor": "IMPL 2.1.1", + "condition": null, + "requirement": "Die Identität potenzieller Beschäftigter wird verifiziert (z. B. Prüfung von Ausweisdokumenten).", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-S1", + "policy": "R05", + "control": "2.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.1-S1", + "impl_anchor": "IMPL 2.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die persönliche Eignung potenzieller Beschäftigter wird mit einfachen Methoden überprüft (z. B. Vorstellungsgespräch).", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.1-S2", + "policy": "R05", + "control": "2.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.1-S2", + "impl_anchor": "IMPL 2.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine erweiterte Eignungsprüfung abhängig vom Arbeitsbereich und der Tätigkeit wird durchgeführt (z. B. Assessment-Center, Prüfung von Referenzen, Zeugnissen und Führungszeugnissen).", + "link": "{{LINK:R05#2.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-M1", + "policy": "R05", + "control": "2.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.2-M1", + "impl_anchor": "IMPL 2.1.2", + "condition": null, + "requirement": "Eine Vertraulichkeitsverpflichtung ist in Kraft.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-M2", + "policy": "R05", + "control": "2.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.2-M2", + "impl_anchor": "IMPL 2.1.2", + "condition": null, + "requirement": "Eine Verpflichtung zur Einhaltung der Informationssicherheitsrichtlinien ist in Kraft.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-S1", + "policy": "R05", + "control": "2.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.2-S1", + "impl_anchor": "IMPL 2.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine über den Arbeitsvertrag hinausgehende Vertraulichkeitsverpflichtung ist in Kraft.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-S2", + "policy": "R05", + "control": "2.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.2-S2", + "impl_anchor": "IMPL 2.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Informationssicherheitsaspekte werden in den Arbeitsverträgen der Beschäftigten berücksichtigt.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.2-S3", + "policy": "R05", + "control": "2.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.2-S3", + "impl_anchor": "IMPL 2.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Verfahren zum Umgang mit Verstößen gegen diese Verpflichtungen ist beschrieben.", + "link": "{{LINK:R05#2.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-14" + ] + }, + { + "id": "2.1.3-M1", + "policy": "R05", + "control": "2.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.3-M1", + "impl_anchor": "IMPL 2.1.3", + "condition": null, + "requirement": "Beschäftigte werden geschult und sensibilisiert.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "2.1.3-S1", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S1", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Konzept für Sensibilisierung und Schulung der Beschäftigten ist erstellt.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-12" + ] + }, + { + "id": "2.1.3-S2", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S2", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Zielgruppen für Schulungs- und Sensibilisierungsmaßnahmen (z. B. Führungskräfte, Administratoren, Beschäftigte mit Zugang zu Kundennetzen, Fertigungspersonal) sind identifiziert und im Konzept berücksichtigt.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S3", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S3", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Das Konzept ist durch die verantwortliche Leitung genehmigt.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S4", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S4", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Schulungs- und Sensibilisierungsmaßnahmen werden regelmäßig und anlassbezogen durchgeführt.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S5", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S5", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Teilnahme an Schulungs- und Sensibilisierungsmaßnahmen wird dokumentiert.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.3-S6", + "policy": "R05", + "control": "2.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.3-S6", + "impl_anchor": "IMPL 2.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ansprechpartner für Informationssicherheit sind den Beschäftigten bekannt.", + "link": "{{LINK:R05#2.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-M1", + "policy": "R06", + "control": "2.1.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 2.1.4-M1", + "impl_anchor": "IMPL 2.1.4", + "condition": null, + "requirement": "Die Anforderungen an mobiles Arbeiten sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-S1", + "policy": "R06", + "control": "2.1.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.4-S1", + "impl_anchor": "IMPL 2.1.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die einschlägigen Aspekte des mobilen Arbeitens werden berücksichtigt.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-S2", + "policy": "R06", + "control": "2.1.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 2.1.4-S2", + "impl_anchor": "IMPL 2.1.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Sensibilisierung der Beschäftigten.", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "2.1.4-H1", + "policy": "R06", + "control": "2.1.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 2.1.4-H1", + "impl_anchor": "IMPL 2.1.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Schutzmaßnahmen gegen Abhören und Einsehen sind umgesetzt. (C)", + "link": "{{LINK:R06#2.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-M1", + "policy": "R07", + "control": "3.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.1-M1", + "impl_anchor": "IMPL 3.1.1", + "condition": null, + "requirement": "Ein Sicherheitszonenkonzept einschließlich zugehöriger Schutzmaßnahmen auf Basis der Anforderungen an die Handhabung von Informationswerten ist vorhanden.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-M2", + "policy": "R07", + "control": "3.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.1-M2", + "impl_anchor": "IMPL 3.1.1", + "condition": null, + "requirement": "Die definierten Schutzmaßnahmen sind umgesetzt.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-M3", + "policy": "R07", + "control": "3.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.1-M3", + "impl_anchor": "IMPL 3.1.1", + "condition": null, + "requirement": "Der Verhaltenskodex für Sicherheitszonen ist allen beteiligten Personen bekannt.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.1-S1", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S1", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Verfahren für die Vergabe und den Entzug von Zutrittsrechten sind etabliert.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S2", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S2", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Richtlinien für das Besuchermanagement (einschließlich Registrierung und Begleitung von Besuchern) sind definiert.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S3", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S3", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Richtlinien für das Mitführen und Nutzen mobiler IT-Geräte und Datenträger (z. B. Registrierung, Kennzeichnungspflichten) sind definiert und umgesetzt.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S4", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S4", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Netzwerk-/Infrastrukturkomponenten (eigene oder Kundennetze) sind gegen unbefugten Zugriff geschützt.", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-S5", + "policy": "R07", + "control": "3.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.1-S5", + "impl_anchor": "IMPL 3.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Externe Liegenschaften zur Speicherung/Verarbeitung von Informationswerten sind im Zonenkonzept berücksichtigt (z. B. Lagerräume, Werkstätten, Teststrecken, Rechenzentren).", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-17" + ] + }, + { + "id": "3.1.1-H1", + "policy": "R07", + "control": "3.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 3.1.1-H1", + "impl_anchor": "IMPL 3.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Schutzmaßnahmen gegen einfaches Abhören und Einsehen sind umgesetzt. (C)", + "link": "{{LINK:R07#3.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.4-M1", + "policy": "R06", + "control": "3.1.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 3.1.4-M1", + "impl_anchor": "IMPL 3.1.4", + "condition": null, + "requirement": "Die Anforderungen an mobile IT-Geräte und mobile Datenträger sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.4-S1", + "policy": "R06", + "control": "3.1.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 3.1.4-S1", + "impl_anchor": "IMPL 3.1.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Registrierung der IT-Geräte.", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "3.1.4-H1", + "policy": "R06", + "control": "3.1.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 3.1.4-H1", + "impl_anchor": "IMPL 3.1.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Generelle Verschlüsselung mobiler Datenträger bzw. der darauf gespeicherten Informationswerte. Wo technisch nicht machbar, werden Informationen durch gleichwertige Maßnahmen geschützt. (C, I)", + "link": "{{LINK:R06#3.1.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.1-M1", + "policy": "R08", + "control": "4.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.1-M1", + "impl_anchor": "IMPL 4.1.1", + "condition": null, + "requirement": "Die Anforderungen an den Umgang mit Identifikationsmitteln über den gesamten Lebenszyklus sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.1-S1", + "policy": "R08", + "control": "4.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.1-S1", + "impl_anchor": "IMPL 4.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Identifikationsmittel können nur unter kontrollierten Bedingungen erstellt werden.", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.1.1-H1", + "policy": "R08", + "control": "4.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 4.1.1-H1", + "impl_anchor": "IMPL 4.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Eine Strategie zur Sperrung oder Ungültigmachung von Identifikationsmitteln im Verlustfall ist vorbereitet und soweit möglich umgesetzt. (C, I, A)", + "link": "{{LINK:R08#4.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-M1", + "policy": "R08", + "control": "4.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.2-M1", + "impl_anchor": "IMPL 4.1.2", + "condition": null, + "requirement": "Die Verfahren zur Benutzerauthentifizierung sind auf Basis einer Risikobewertung ausgewählt; mögliche Angriffsszenarien (z. B. direkte Erreichbarkeit über das Internet) wurden berücksichtigt.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-M2", + "policy": "R08", + "control": "4.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.2-M2", + "impl_anchor": "IMPL 4.1.2", + "condition": null, + "requirement": "Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-S1", + "policy": "R08", + "control": "4.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.2-S1", + "impl_anchor": "IMPL 4.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Authentifizierungsverfahren sind auf Basis der geschäftlichen und sicherheitsrelevanten Anforderungen definiert und umgesetzt.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-S2", + "policy": "R08", + "control": "4.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.2-S2", + "impl_anchor": "IMPL 4.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Benutzer werden mindestens durch starke Passwörter nach bewährten und anerkannten Praktiken authentifiziert.", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-S3", + "policy": "R08", + "control": "4.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.2-S3", + "impl_anchor": "IMPL 4.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt (z. B. Privileged Access Management, Zwei-Faktor-Authentifizierung).", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-H1", + "policy": "R08", + "control": "4.1.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 4.1.2-H1", + "impl_anchor": "IMPL 4.1.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Abhängig von der Risikobewertung sind Authentifizierung und Zugangskontrolle durch ergänzende Maßnahmen verstärkt (z. B. kontinuierliche Zugriffsüberwachung, starke Authentifizierung, automatische Abmeldung, Sperre bei Inaktivität, Brute-Force-Prävention). (C, I, A)", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.2-V1", + "policy": "R08", + "control": "4.1.2", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 4.1.2-V1", + "impl_anchor": "IMPL 4.1.2-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Vor dem Zugriff auf Daten mit sehr hohem Schutzbedarf werden Benutzer mittels starker Authentifizierung (z. B. Zwei-Faktor) nach dem Stand der Technik authentifiziert. (C, I)", + "link": "{{LINK:R08#4.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M1", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M1", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Das Erstellen, Ändern und Löschen von Benutzerkonten wird durchgeführt.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.1.3-M2", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M2", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Eindeutige und personalisierte Benutzerkonten werden verwendet.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M3", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M3", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Die Nutzung von Sammelkonten ist geregelt (z. B. beschränkt auf Fälle, in denen Nachvollziehbarkeit verzichtbar ist).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M4", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M4", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Benutzerkonten werden unmittelbar nach dem Ausscheiden des Nutzers deaktiviert (z. B. bei Vertragsende).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M5", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M5", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Benutzerkonten werden regelmäßig überprüft.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M6", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M6", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Die Anmeldeinformationen werden dem Nutzer auf sichere Weise bereitgestellt.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-M7", + "policy": "R08", + "control": "4.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.1.3-M7", + "impl_anchor": "IMPL 4.1.3", + "condition": null, + "requirement": "Eine Richtlinie zum Umgang mit Anmeldeinformationen ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S1", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S1", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Basiskonto mit minimalen Zugriffsrechten und Funktionalitäten existiert und wird genutzt.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S10", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S10", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Interaktive Anmeldung für Dienstkonten (technische Konten) wird technisch verhindert.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S2", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S2", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Vom Hersteller vorkonfigurierte Standardkonten und -passwörter sind deaktiviert (z. B. Sperren oder Passwortänderung).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S3", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S3", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Benutzerkonten werden durch die verantwortliche Stelle erstellt oder autorisiert.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S4", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S4", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Das Erstellen von Benutzerkonten unterliegt einem Genehmigungsprozess (Vier-Augen-Prinzip).", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S5", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S5", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Benutzerkonten von Dienstleistern werden nach Abschluss ihrer Aufgabe deaktiviert.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S6", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S6", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Fristen für das Deaktivieren und Löschen von Benutzerkonten sind definiert.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S7", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S7", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Verwendung von Standardpasswörtern wird technisch verhindert.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S8", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S8", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Bei starker Authentifizierung ist die Nutzung des Mediums (z. B. Besitzfaktor) sicher.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.1.3-S9", + "policy": "R08", + "control": "4.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.1.3-S9", + "impl_anchor": "IMPL 4.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Benutzerkonten werden regelmäßig überprüft; dies umfasst auch Konten in IT-Systemen von Kunden.", + "link": "{{LINK:R08#4.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-M1", + "policy": "R08", + "control": "4.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.2.1-M1", + "impl_anchor": "IMPL 4.2.1", + "condition": null, + "requirement": "Die Anforderungen an die Verwaltung von Zugriffsrechten (Autorisierung) sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.2.1-M2", + "policy": "R08", + "control": "4.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 4.2.1-M2", + "impl_anchor": "IMPL 4.2.1", + "condition": null, + "requirement": "Die für normale und privilegierte Benutzerkonten sowie technische Konten vergebenen Zugriffsrechte werden regelmäßig überprüft, auch in IT-Systemen von Kunden.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.2.1-S1", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S1", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Strategien zur Autorisierung von Zugriffen auf Informationen sind vorbereitet.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-03" + ] + }, + { + "id": "4.2.1-S2", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S2", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Autorisierungsrollen werden verwendet.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-S3", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S3", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Rechte werden nach dem Need-to-use-Prinzip und gemäß Rolle und/oder Verantwortungsbereich vergeben.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-S4", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S4", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Normale Benutzerkonten erhalten keine privilegierten Zugriffsrechte.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-S5", + "policy": "R08", + "control": "4.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 4.2.1-S5", + "impl_anchor": "IMPL 4.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Zugriffsrechte des Nutzers werden nach Änderung seiner Verantwortlichkeiten aktualisiert.", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-H1", + "policy": "R08", + "control": "4.2.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 4.2.1-H1", + "impl_anchor": "IMPL 4.2.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Zugriffsrechte werden durch den verantwortlichen internen Information Officer genehmigt. (C, I, A)", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-V1", + "policy": "R08", + "control": "4.2.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 4.2.1-V1", + "impl_anchor": "IMPL 4.2.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Informationen werden auf Inhaltsebene (z. B. Dateiebene) verschlüsselt gespeichert, um unbefugten Zugriff (auch privilegierter Nutzer) zu verhindern. Wo Verschlüsselung nicht machbar ist, greifen gleichwertige Maßnahmen. (C)", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "4.2.1-V2", + "policy": "R08", + "control": "4.2.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 4.2.1-V2", + "impl_anchor": "IMPL 4.2.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Bestehende Zugriffsrechte werden in kürzeren Abständen (z. B. quartalsweise) überprüft. (C)", + "link": "{{LINK:R08#4.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.1-M1", + "policy": "R09", + "control": "5.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.1-M1", + "impl_anchor": "IMPL 5.1.1", + "condition": null, + "requirement": "Alle eingesetzten kryptografischen Verfahren (z. B. Verschlüsselung, Signatur, Hash-Algorithmen, Protokolle) bieten die im jeweiligen Anwendungsfeld erforderliche Sicherheit nach anerkanntem Industriestandard, soweit rechtlich möglich.", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.1-S1", + "policy": "R09", + "control": "5.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.1-S1", + "impl_anchor": "IMPL 5.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Konzept für den Einsatz von Kryptografie ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.1-H1", + "policy": "R09", + "control": "5.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.1.1-H1", + "impl_anchor": "IMPL 5.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) sind bestimmt und erfüllt. (C, I)", + "link": "{{LINK:R09#5.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-M1", + "policy": "R09", + "control": "5.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.2-M1", + "impl_anchor": "IMPL 5.1.2", + "condition": null, + "requirement": "Die zur Informationsübertragung genutzten Netzdienste sind identifiziert und dokumentiert.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.2-M2", + "policy": "R09", + "control": "5.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.2-M2", + "impl_anchor": "IMPL 5.1.2", + "condition": null, + "requirement": "Richtlinien und Verfahren entsprechend den Klassifizierungsanforderungen für die Nutzung von Netzdiensten sind definiert und umgesetzt.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-M3", + "policy": "R09", + "control": "5.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.1.2-M3", + "impl_anchor": "IMPL 5.1.2", + "condition": null, + "requirement": "Maßnahmen zum Schutz übertragener Inhalte gegen unbefugten Zugriff sind umgesetzt.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-S1", + "policy": "R09", + "control": "5.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.2-S1", + "impl_anchor": "IMPL 5.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Maßnahmen zur Sicherstellung korrekter Adressierung und korrekter Informationsübertragung sind umgesetzt.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-07" + ] + }, + { + "id": "5.1.2-S2", + "policy": "R09", + "control": "5.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.2-S2", + "impl_anchor": "IMPL 5.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Elektronischer Datenaustausch erfolgt mittels Inhalts- oder Transportverschlüsselung entsprechend der jeweiligen Klassifizierung.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-S3", + "policy": "R09", + "control": "5.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.1.2-S3", + "impl_anchor": "IMPL 5.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Fernzugriffsverbindungen zum Netzwerk der Organisation verfügen über angemessene Sicherheitsmerkmale; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-H1", + "policy": "R09", + "control": "5.1.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.1.2-H1", + "impl_anchor": "IMPL 5.1.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Informationen werden verschlüsselt übertragen (mindestens Transportverschlüsselung) oder durch gleichwertig wirksame Maßnahmen geschützt. (C)", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.1.2-V1", + "policy": "R09", + "control": "5.1.2", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.1.2-V1", + "impl_anchor": "IMPL 5.1.2-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Informationen werden inhaltsverschlüsselt übertragen. (C)", + "link": "{{LINK:R09#5.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-M1", + "policy": "R10", + "control": "5.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.1-M1", + "impl_anchor": "IMPL 5.2.1", + "condition": null, + "requirement": "Informationssicherheitsanforderungen für Änderungen an Organisation, Geschäftsprozessen und IT-Systemen sind bestimmt und erfüllt.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04" + ] + }, + { + "id": "5.2.1-S1", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S1", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein formales Genehmigungsverfahren ist etabliert.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-S2", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S2", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die möglichen Auswirkungen von Änderungen auf die Informationssicherheit werden bewertet.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-S3", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S3", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Änderungen mit Auswirkung auf die Informationssicherheit werden geplant und getestet.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-S4", + "policy": "R10", + "control": "5.2.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.1-S4", + "impl_anchor": "IMPL 5.2.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Verfahren zum Rückfall (Fallback) in Fehlerfällen werden berücksichtigt.", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.1-H1", + "policy": "R10", + "control": "5.2.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.1-H1", + "impl_anchor": "IMPL 5.2.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Einhaltung der Informationssicherheitsanforderungen wird während und nach den Änderungen überprüft. (C, I, A)", + "link": "{{LINK:R10#5.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.2-M1", + "policy": "R10", + "control": "5.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.2-M1", + "impl_anchor": "IMPL 5.2.2", + "condition": null, + "requirement": "Die IT-Systeme wurden einer Risikobewertung unterzogen, um die Notwendigkeit ihrer Trennung in Entwicklungs-, Test- und Produktivsysteme zu bestimmen.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.2-M2", + "policy": "R10", + "control": "5.2.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.2-M2", + "impl_anchor": "IMPL 5.2.2", + "condition": null, + "requirement": "Eine Segmentierung ist auf Basis der Ergebnisse der Risikoanalyse umgesetzt.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.2-S1", + "policy": "R10", + "control": "5.2.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.2-S1", + "impl_anchor": "IMPL 5.2.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Anforderungen an Entwicklungs- und Testumgebungen sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R10#5.2.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-M1", + "policy": "R10", + "control": "5.2.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.3-M1", + "impl_anchor": "IMPL 5.2.3", + "condition": null, + "requirement": "Anforderungen zum Schutz vor Schadsoftware sind bestimmt.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-M2", + "policy": "R10", + "control": "5.2.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.3-M2", + "impl_anchor": "IMPL 5.2.3", + "condition": null, + "requirement": "Technische und organisatorische Maßnahmen zum Schutz vor Schadsoftware sind definiert und umgesetzt.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S1", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S1", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Unnötige Netzwerkdienste sind deaktiviert.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S2", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S2", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Der Zugriff auf Netzwerkdienste ist durch geeignete Schutzmaßnahmen auf das Notwendige beschränkt.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S3", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S3", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Schutzsoftware gegen Schadsoftware ist installiert und wird regelmäßig automatisch aktualisiert (z. B. Virenscanner).", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S4", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S4", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Empfangene Dateien und Software werden vor der Ausführung automatisch auf Schadsoftware geprüft (On-Access-Scan).", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S5", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S5", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Der gesamte Datenbestand aller Systeme wird regelmäßig auf Schadsoftware geprüft.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S6", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S6", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Über zentrale Gateways übertragene Daten (z. B. E-Mail, Internet, Fremdnetze) werden automatisch durch Schutzsoftware geprüft.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S7", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S7", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Maßnahmen, die verhindern, dass Schutzsoftware durch Nutzer deaktiviert oder verändert wird, sind definiert und umgesetzt.", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.3-S8", + "policy": "R10", + "control": "5.2.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.3-S8", + "impl_anchor": "IMPL 5.2.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Für IT-Systeme ohne Schutzsoftware sind alternative Maßnahmen umgesetzt (z. B. besondere Resilienz, wenige Dienste, keine aktiven Nutzer, Netzisolation).", + "link": "{{LINK:R10#5.2.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M1", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M1", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Informationssicherheitsanforderungen an den Umgang mit Ereignisprotokollen sind bestimmt und erfüllt.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "5.2.4-M2", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M2", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Sicherheitsrelevante Anforderungen an die Protokollierung von Aktivitäten von Administratoren und Nutzern sind bestimmt und erfüllt.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M3", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M3", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Die eingesetzten IT-Systeme werden hinsichtlich der Notwendigkeit der Protokollierung bewertet.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M4", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M4", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Bei Nutzung externer IT-Dienste werden Informationen zu den Überwachungsmöglichkeiten eingeholt und in der Bewertung berücksichtigt.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-M5", + "policy": "R10", + "control": "5.2.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.4-M5", + "impl_anchor": "IMPL 5.2.4", + "condition": null, + "requirement": "Ereignisprotokolle werden regelmäßig auf Richtlinienverstöße und auffällige Probleme geprüft, unter Einhaltung der zulässigen rechtlichen und organisatorischen Vorgaben.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-S1", + "policy": "R10", + "control": "5.2.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.4-S1", + "impl_anchor": "IMPL 5.2.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Verfahren zur Eskalation relevanter Ereignisse an die verantwortliche Stelle ist definiert und etabliert.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-13" + ] + }, + { + "id": "5.2.4-S2", + "policy": "R10", + "control": "5.2.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.4-S2", + "impl_anchor": "IMPL 5.2.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ereignisprotokolle (Inhalt und Metadaten) sind gegen Veränderung geschützt (z. B. durch eine dedizierte Umgebung).", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-S3", + "policy": "R10", + "control": "5.2.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.4-S3", + "impl_anchor": "IMPL 5.2.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine angemessene Überwachung und Aufzeichnung aller informationssicherheitsrelevanten Aktionen im Netzwerk ist etabliert.", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-H1", + "policy": "R10", + "control": "5.2.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.4-H1", + "impl_anchor": "IMPL 5.2.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Sicherheitsrelevante Anforderungen an den Umgang mit Ereignisprotokollen, z. B. vertragliche Anforderungen, sind bestimmt und umgesetzt. (C, I, A)", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-H2", + "policy": "R10", + "control": "5.2.4", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.4-H2", + "impl_anchor": "IMPL 5.2.4-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Ereignisse zu Auf- und Abbau von Fernzugriffssitzungen (z. B. Fernwartung) werden protokolliert. (C, I, A)", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.4-V1", + "policy": "R10", + "control": "5.2.4", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.4-V1", + "impl_anchor": "IMPL 5.2.4-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Protokollierung jedes Zugriffs auf Daten mit sehr hohem Schutzbedarf, soweit technisch machbar und rechtlich/organisatorisch zulässig. (C, I)", + "link": "{{LINK:R10#5.2.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-M1", + "policy": "R10", + "control": "5.2.5", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.5-M1", + "impl_anchor": "IMPL 5.2.5", + "condition": null, + "requirement": "Informationen über technische Schwachstellen der eingesetzten IT-Systeme werden erhoben (z. B. Herstellerinfos, System-Audits, CVE-Datenbank).", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-04", + "VA-06" + ] + }, + { + "id": "5.2.5-M2", + "policy": "R10", + "control": "5.2.5", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.5-M2", + "impl_anchor": "IMPL 5.2.5", + "condition": null, + "requirement": "Potenziell betroffene IT-Systeme und Software werden identifiziert und das durch die Schwachstelle verursachte Risiko wird bewertet.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-M3", + "policy": "R10", + "control": "5.2.5", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.5-M3", + "impl_anchor": "IMPL 5.2.5", + "condition": null, + "requirement": "Risiken aus Schwachstellen werden behandelt.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-S1", + "policy": "R10", + "control": "5.2.5", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.5-S1", + "impl_anchor": "IMPL 5.2.5", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein angemessenes Patch-Management ist definiert und umgesetzt (z. B. Patch-Test und -Installation).", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-06" + ] + }, + { + "id": "5.2.5-S2", + "policy": "R10", + "control": "5.2.5", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.5-S2", + "impl_anchor": "IMPL 5.2.5", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Risikominimierende Maßnahmen werden bei Bedarf umgesetzt.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.5-S3", + "policy": "R10", + "control": "5.2.5", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.5-S3", + "impl_anchor": "IMPL 5.2.5", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die erfolgreiche Installation von Patches wird in geeigneter Weise verifiziert.", + "link": "{{LINK:R10#5.2.5}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M1", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M1", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "Anforderungen an die Prüfung (Audit) von IT-Systemen oder -Diensten sind bestimmt.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-06" + ] + }, + { + "id": "5.2.6-M2", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M2", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "Der Umfang der Systemprüfung wird rechtzeitig festgelegt.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M3", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M3", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "System- oder Dienstprüfungen werden mit Betreiber und Nutzern der IT-Systeme/-Dienste abgestimmt.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M4", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M4", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "Die Ergebnisse von System-/Dienstprüfungen werden nachvollziehbar gespeichert und der zuständigen Leitung berichtet.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-M5", + "policy": "R10", + "control": "5.2.6", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.6-M5", + "impl_anchor": "IMPL 5.2.6", + "condition": null, + "requirement": "Aus den Ergebnissen werden Maßnahmen abgeleitet und in angemessener Frist umgesetzt.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-S1", + "policy": "R10", + "control": "5.2.6", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.6-S1", + "impl_anchor": "IMPL 5.2.6", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "System- und Dienstprüfungen werden unter Berücksichtigung möglicher Sicherheitsrisiken (z. B. Störungen) geplant.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-S2", + "policy": "R10", + "control": "5.2.6", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.6-S2", + "impl_anchor": "IMPL 5.2.6", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Regelmäßige System- oder Dienstprüfungen werden durchgeführt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-S3", + "policy": "R10", + "control": "5.2.6", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.6-S3", + "impl_anchor": "IMPL 5.2.6", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Innerhalb einer angemessenen Frist nach Abschluss der Prüfung wird ein Bericht erstellt.", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-H1", + "policy": "R10", + "control": "5.2.6", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.6-H1", + "impl_anchor": "IMPL 5.2.6-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Für kritische IT-Systeme/-Dienste wurden zusätzliche Prüfanforderungen identifiziert und werden erfüllt (z. B. dienstspezifische Tests/Werkzeuge und/oder manuelle Penetrationstests, risikobasierte Intervalle). (A)", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.6-V1", + "policy": "R10", + "control": "5.2.6", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.6-V1", + "impl_anchor": "IMPL 5.2.6-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "IT-Systeme und -Dienste werden regelmäßig auf Schwachstellen gescannt. Für nicht scanbare Systeme/Dienste sind geeignete Schutzmaßnahmen umzusetzen. (C, I, A)", + "link": "{{LINK:R10#5.2.6}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-M1", + "policy": "R10", + "control": "5.2.7", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.7-M1", + "impl_anchor": "IMPL 5.2.7", + "condition": null, + "requirement": "Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und erfüllt.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-M2", + "policy": "R10", + "control": "5.2.7", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.7-M2", + "impl_anchor": "IMPL 5.2.7", + "condition": null, + "requirement": "Anforderungen an die Netzsegmentierung sind bestimmt und erfüllt.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-S1", + "policy": "R10", + "control": "5.2.7", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.7-S1", + "impl_anchor": "IMPL 5.2.7", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Verfahren für das Management und die Steuerung von Netzwerken sind definiert.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-S2", + "policy": "R10", + "control": "5.2.7", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.7-S2", + "impl_anchor": "IMPL 5.2.7", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Für eine risikobasierte Netzsegmentierung werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.7-H1", + "policy": "R10", + "control": "5.2.7", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.7-H1", + "impl_anchor": "IMPL 5.2.7-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Erweiterte Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und umgesetzt. (C, I, A)", + "link": "{{LINK:R10#5.2.7}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-M1", + "policy": "R04", + "control": "5.2.8", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.8-M1", + "impl_anchor": "IMPL 5.2.8", + "condition": null, + "requirement": "Kritische IT-Dienste sind identifiziert und die Geschäftsauswirkung wird berücksichtigt.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "5.2.8-M2", + "policy": "R04", + "control": "5.2.8", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.8-M2", + "impl_anchor": "IMPL 5.2.8", + "condition": null, + "requirement": "Anforderungen und Verantwortlichkeiten für Kontinuität und Wiederherstellung dieser IT-Dienste sind relevanten Stakeholdern bekannt und erfüllt.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-S1", + "policy": "R04", + "control": "5.2.8", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.8-S1", + "impl_anchor": "IMPL 5.2.8", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Kritische IT-Systeme sind identifiziert; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-02" + ] + }, + { + "id": "5.2.8-S2", + "policy": "R04", + "control": "5.2.8", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.8-S2", + "impl_anchor": "IMPL 5.2.8", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine Kontinuitätsplanung existiert und wird regelmäßig überprüft und aktualisiert.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-S3", + "policy": "R04", + "control": "5.2.8", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.8-S3", + "impl_anchor": "IMPL 5.2.8", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Kontinuitätsplanung umfasst mindestens (D)DoS-Angriffe, erfolgreiche Ransomware-Angriffe und andere Sabotage, Systemausfallszenarien sowie Naturkatastrophen, die kritische IT-Systeme betreffen.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H1", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H1", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Kontinuitätsplanung enthält vordefinierte Zeitrahmen (Recovery Time Objective) für die Wiederaufnahme des Betriebs. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H2", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H2", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Angemessene SLAs mit externen Dienstleistern entsprechend der Kontinuitätsplanung bestehen. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H3", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H3", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Kontinuitätspläne umfassen die Koordination vertraglich vereinbarter Kommunikation mit Geschäftspartnern. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H4", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H4", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Kontinuitätsplanung wird regelmäßig getestet, inkl. vollständiger Wiederherstellung in einen bekannten Zustand und Einhaltung definierter Zielzeiten. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H5", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H5", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Eine Backup- und Wiederherstellungsstrategie für kritische IT-Dienste und Informationen ist definiert und umgesetzt. (C, I, A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H6", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H6", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugte Veränderung/Löschung durch Schadsoftware geschützt. (I, A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-H7", + "policy": "R04", + "control": "5.2.8", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-H7", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugten Zugriff durch Schadsoftware oder Betreiber geschützt. (C, I)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-V1", + "policy": "R04", + "control": "5.2.8", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-V1", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Die Kontinuitätsplanung ist mit den Kontinuitätsplänen relevanter externer Dienstleister abgestimmt. (A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-V2", + "policy": "R04", + "control": "5.2.8", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-V2", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Die Fortführung wesentlicher Kern- und Geschäftsfunktionen mit minimalem oder keinem Verlust an Betriebskontinuität ist möglich; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.8-V3", + "policy": "R04", + "control": "5.2.8", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.8-V3", + "impl_anchor": "IMPL 5.2.8-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Die Kontinuitätsplanung wird regelmäßig getestet. Testszenarien, Ergebnisse und Lessons Learned werden aufgezeichnet. (I, A)", + "link": "{{LINK:R04#5.2.8}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-M1", + "policy": "R10", + "control": "5.2.9", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.9-M1", + "impl_anchor": "IMPL 5.2.9", + "condition": null, + "requirement": "Backup-Konzepte existieren für relevante IT-Systeme. Angemessene Schutzmaßnahmen für Vertraulichkeit, Integrität und Verfügbarkeit der Datensicherungen werden berücksichtigt.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "5.2.9-M2", + "policy": "R10", + "control": "5.2.9", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.2.9-M2", + "impl_anchor": "IMPL 5.2.9", + "condition": null, + "requirement": "Wiederherstellungskonzepte existieren für relevante IT-Dienste.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "5.2.9-S1", + "policy": "R10", + "control": "5.2.9", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.2.9-S1", + "impl_anchor": "IMPL 5.2.9", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Für jeden relevanten IT-Dienst existiert ein Backup- und Wiederherstellungskonzept. Abhängigkeiten zwischen IT-Diensten und die Reihenfolge der Wiederherstellung werden berücksichtigt.", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-05" + ] + }, + { + "id": "5.2.9-H1", + "policy": "R10", + "control": "5.2.9", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-H1", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Backup- und Wiederherstellungskonzepte werden methodisch in regelmäßigen Abständen überprüft. (A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-H2", + "policy": "R10", + "control": "5.2.9", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-H2", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die grundsätzliche Wiederherstellbarkeit wird berücksichtigt und getestet (z. B. Stichprobentests, Testsysteme). (I, A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-V1", + "policy": "R10", + "control": "5.2.9", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-V1", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "(Zusätzliche) Backups werden über Offline-Verfahren, unveränderliche (immutable) Backups oder eine isolierte IAM-Lösung durchgeführt. (I, A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-V2", + "policy": "R10", + "control": "5.2.9", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-V2", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Wiederherstellungsverfahren werden methodisch in regelmäßigen Abständen technisch getestet. (I, A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.2.9-V3", + "policy": "R10", + "control": "5.2.9", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.2.9-V3", + "impl_anchor": "IMPL 5.2.9-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Geografische Redundanz wird in Backup- und Wiederherstellungskonzepten berücksichtigt. (A)", + "link": "{{LINK:R10#5.2.9}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.3.1-M1", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M1", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "Die mit Design und Entwicklung eines IT-Dienstes verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-M2", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M2", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "Die mit Beschaffung oder Erweiterung von IT-Diensten und -Komponenten verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-M3", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M3", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "Informationssicherheitsanforderungen im Zusammenhang mit Änderungen an entwickelten IT-Diensten werden berücksichtigt.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-M4", + "policy": "R11", + "control": "5.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.1-M4", + "impl_anchor": "IMPL 5.3.1", + "condition": null, + "requirement": "Systemabnahmetests werden unter Berücksichtigung der Informationssicherheitsanforderungen durchgeführt.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S1", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S1", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Anforderungsspezifikationen werden erstellt; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S2", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S2", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Anforderungsspezifikationen werden gegen die Informationssicherheitsanforderungen geprüft.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S3", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S3", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Der IT-Dienst wird vor Produktivnutzung auf Einhaltung der Spezifikationen geprüft.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S4", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S4", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Nutzung von Produktivdaten zu Testzwecken wird soweit möglich vermieden (ggf. Anonymisierung/Pseudonymisierung); dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-S5", + "policy": "R11", + "control": "5.3.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.1-S5", + "impl_anchor": "IMPL 5.3.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Testsysteme erhalten Schutzmaßnahmen vergleichbar zur Produktivumgebung, wenn Produktivdaten für Tests genutzt werden.", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.1-V1", + "policy": "R11", + "control": "5.3.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 5.3.1-V1", + "impl_anchor": "IMPL 5.3.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Die Sicherheit zweckgebauter oder wesentlich angepasster Software wird bei Inbetriebnahme, bei wesentlichen Änderungen oder regelmäßig getestet (z. B. Penetrationstest). (C, I, A)", + "link": "{{LINK:R11#5.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-M1", + "policy": "R11", + "control": "5.3.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.2-M1", + "impl_anchor": "IMPL 5.3.2", + "condition": null, + "requirement": "Anforderungen an die Informationssicherheit von Netzdiensten sind bestimmt und erfüllt.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-S1", + "policy": "R11", + "control": "5.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.2-S1", + "impl_anchor": "IMPL 5.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Verfahren zur Absicherung und Nutzung von Netzdiensten ist definiert und umgesetzt.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-S2", + "policy": "R11", + "control": "5.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.2-S2", + "impl_anchor": "IMPL 5.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Anforderungen werden in Form von SLAs vereinbart.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-S3", + "policy": "R11", + "control": "5.3.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.2-S3", + "impl_anchor": "IMPL 5.3.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Angemessene Redundanzlösungen sind umgesetzt.", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.2-H1", + "policy": "R11", + "control": "5.3.2", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 5.3.2-H1", + "impl_anchor": "IMPL 5.3.2-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Verfahren zur Überwachung der Qualität des Netzverkehrs (z. B. Traffic-Flow-Analysen, Verfügbarkeitsmessungen) sind definiert und werden durchgeführt. (A)", + "link": "{{LINK:R11#5.3.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-16" + ] + }, + { + "id": "5.3.3-S1", + "policy": "R11", + "control": "5.3.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.3-S1", + "impl_anchor": "IMPL 5.3.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Eine Beschreibung des Beendigungsprozesses ist vorhanden, an Änderungen angepasst und vertraglich geregelt.", + "link": "{{LINK:R11#5.3.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "5.3.4-M1", + "policy": "R12", + "control": "5.3.4", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 5.3.4-M1", + "impl_anchor": "IMPL 5.3.4", + "condition": null, + "requirement": "Eine wirksame Trennung (z. B. Mandantentrennung) verhindert den Zugriff unbefugter Nutzer anderer Organisationen auf eigene Informationen.", + "link": "{{LINK:R12#5.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-S1", + "policy": "R12", + "control": "5.3.4", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 5.3.4-S1", + "impl_anchor": "IMPL 5.3.4", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Das Trennungskonzept des Anbieters ist dokumentiert und an Änderungen angepasst; dabei werden die einschlägigen Aspekte berücksichtigt.", + "link": "{{LINK:R12#5.3.4}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-M1", + "policy": "R12", + "control": "5.3.4-KI", + "level": "must", + "type": "MUSS", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-M1", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": null, + "requirement": "Der Einsatz von KI-/GenAI-Diensten ist geregelt; es werden nur freigegebene Dienste genutzt.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-M2", + "policy": "R12", + "control": "5.3.4-KI", + "level": "must", + "type": "MUSS", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-M2", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": null, + "requirement": "Die Eingabe vertraulicher oder personenbezogener Informationen in nicht freigegebene KI-Dienste ist untersagt; zulässige Datenklassen je Dienst sind definiert.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-M3", + "policy": "R12", + "control": "5.3.4-KI", + "level": "must", + "type": "MUSS", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-M3", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": null, + "requirement": "Bei freigegebenen KI-Diensten ist geklärt und vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "5.3.4-KI-S1", + "policy": "R12", + "control": "5.3.4-KI", + "level": "should", + "type": "SOLL", + "is_isa": false, + "req_anchor": "REQ 5.3.4-KI-S1", + "impl_anchor": "IMPL 5.3.4-KI", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ergebnisse von KI-Diensten werden vor geschäftskritischer Verwendung geprüft (Human-in-the-Loop); der KI-Einsatz wird dokumentiert und regulatorische Anforderungen (z. B. EU AI Act) berücksichtigt.", + "link": "{{LINK:R12#5.3.4-KI}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-11" + ] + }, + { + "id": "6.1.1-M1", + "policy": "R13", + "control": "6.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.1-M1", + "impl_anchor": "IMPL 6.1.1", + "condition": null, + "requirement": "Auftragnehmer und Partner werden einer Sicherheitsrisikobewertung unterzogen.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.1-M2", + "policy": "R13", + "control": "6.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.1-M2", + "impl_anchor": "IMPL 6.1.1", + "condition": null, + "requirement": "Ein angemessenes Informationssicherheitsniveau wird durch vertragliche Vereinbarungen mit Auftragnehmern und Partnern sichergestellt.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.1-M3", + "policy": "R13", + "control": "6.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.1-M3", + "impl_anchor": "IMPL 6.1.1", + "condition": null, + "requirement": "Sofern zutreffend, werden vertragliche Vereinbarungen mit Auftraggebern/Kunden an Auftragnehmer und Partner weitergegeben.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-S1", + "policy": "R13", + "control": "6.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.1-S1", + "impl_anchor": "IMPL 6.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Auftragnehmer und Partner sind vertraglich verpflichtet, Anforderungen an ein angemessenes Informationssicherheitsniveau an ihre Unterauftragnehmer weiterzugeben.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.1-S2", + "policy": "R13", + "control": "6.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.1-S2", + "impl_anchor": "IMPL 6.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Leistungsberichte und Dokumente von Auftragnehmern und Partnern werden geprüft.", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-H1", + "policy": "R13", + "control": "6.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-H1", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Es wird nachgewiesen, dass das Informationssicherheitsniveau des Lieferanten dem Schutzbedarf angemessen ist (z. B. geprüfter Fragebogen/Selbstauskunft, Attestierung, Zertifikat, Lieferantenaudit). (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-H2", + "policy": "R13", + "control": "6.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-H2", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Der Grad der Erfüllung geforderter Nachweise durch den Lieferanten wird dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-H3", + "policy": "R13", + "control": "6.1.1", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-H3", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Einhaltung vertraglicher Vereinbarungen durch den Lieferanten wird geprüft, dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-V1", + "policy": "R13", + "control": "6.1.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-V1", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Das angemessene Informationssicherheitsniveau sollte durch ein Drittparteien-Audit (angemessenes TISAX-Label o. Ä.) oder ein angemessenes Lieferantenaudit nachgewiesen werden. Ohne Audit muss die Leitung eine risikobasierte Entscheidung zur Fortführung treffen; ein Nachweis dieser Entscheidung existiert. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.1-V2", + "policy": "R13", + "control": "6.1.1", + "level": "vhigh", + "type": "SEHR HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.1-V2", + "impl_anchor": "IMPL 6.1.1-elev", + "condition": "FLAG_VERY_HIGH_PROTECTION", + "requirement": "Vertragliche Verpflichtungen gegenüber Kunden zur Transparenz von Lieferkettenrisiken werden erfüllt. (C, I, A)", + "link": "{{LINK:R13#6.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-M1", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M1", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "Die Vertraulichkeitsanforderungen sind bestimmt und erfüllt.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.2-M2", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M2", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "Anforderungen und Verfahren zur Anwendung von Vertraulichkeitsvereinbarungen sind allen Personen bekannt, die schutzbedürftige Informationen weitergeben.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-M3", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M3", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "Gültige Vertraulichkeitsvereinbarungen werden vor der Weitergabe schutzbedürftiger Informationen abgeschlossen.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-M4", + "policy": "R13", + "control": "6.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.2-M4", + "impl_anchor": "IMPL 6.1.2", + "condition": null, + "requirement": "Die Anforderungen und Verfahren zur Nutzung von Vertraulichkeitsvereinbarungen und zum Umgang mit schutzbedürftigen Informationen werden regelmäßig überprüft.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S1", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S1", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Vorlagen für Vertraulichkeitsvereinbarungen sind vorhanden und auf rechtliche Anwendbarkeit geprüft.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.2-S2", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S2", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Vertraulichkeitsvereinbarungen umfassen beteiligte Personen/Organisationen, Art der Informationen, Gegenstand, Gültigkeitsdauer und Verantwortlichkeiten der verpflichteten Partei.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S3", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S3", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Vertraulichkeitsvereinbarungen enthalten Regelungen zum Umgang mit schutzbedürftigen Informationen über die Vertragsbeziehung hinaus.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S4", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S4", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Möglichkeiten zum Nachweis der Einhaltung (z. B. Prüfung durch unabhängige Dritte oder Auditrechte) sind definiert.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.2-S5", + "policy": "R13", + "control": "6.1.2", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.2-S5", + "impl_anchor": "IMPL 6.1.2", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Ein Prozess zur Überwachung der Gültigkeitsdauer temporärer Vertraulichkeitsvereinbarungen und zur rechtzeitigen Verlängerung ist definiert und umgesetzt.", + "link": "{{LINK:R13#6.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M1", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M1", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "Die betroffenen IT-Dienste sind identifiziert.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-10" + ] + }, + { + "id": "6.1.3-M2", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M2", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "Die für den IT-Dienst relevanten Sicherheitsanforderungen sind bestimmt.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M3", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M3", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "Die für die Umsetzung der Anforderung verantwortliche Organisation ist definiert und sich ihrer Verantwortung bewusst.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M4", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M4", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "Mechanismen für geteilte Verantwortlichkeiten sind spezifiziert und umgesetzt.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-M5", + "policy": "R13", + "control": "6.1.3", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 6.1.3-M5", + "impl_anchor": "IMPL 6.1.3", + "condition": null, + "requirement": "Die verantwortliche Organisation erfüllt ihre jeweiligen Verantwortlichkeiten.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-S1", + "policy": "R13", + "control": "6.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.3-S1", + "impl_anchor": "IMPL 6.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Bei IT-Diensten ist die Konfiguration auf Basis der notwendigen Sicherheitsanforderungen konzipiert, umgesetzt und dokumentiert.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-S2", + "policy": "R13", + "control": "6.1.3", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 6.1.3-S2", + "impl_anchor": "IMPL 6.1.3", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Das verantwortliche Personal ist angemessen geschult.", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H1", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H1", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Eine Liste der betroffenen IT-Dienste und der jeweils verantwortlichen IT-Dienstleister existiert. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H2", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H2", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Anwendbarkeit der ISA-Controls wurde bewertet und dokumentiert. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H3", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H3", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Dienstkonfiguration ist in die regelmäßigen Sicherheitsbewertungen einbezogen. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H4", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H4", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Es wird nachgewiesen, dass die IT-Dienstleister ihre Verantwortung erfüllen. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "6.1.3-H5", + "policy": "R13", + "control": "6.1.3", + "level": "high", + "type": "HOCH", + "is_isa": true, + "req_anchor": "REQ 6.1.3-H5", + "impl_anchor": "IMPL 6.1.3-elev", + "condition": "FLAG_HIGH_PROTECTION", + "requirement": "Die Integration in lokale Schutzmaßnahmen (z. B. sichere Authentifizierungsmechanismen) ist etabliert und dokumentiert. (C, I, A)", + "link": "{{LINK:R13#6.1.3}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "7.1.1-M1", + "policy": "R14", + "control": "7.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.1-M1", + "impl_anchor": "IMPL 7.1.1", + "condition": null, + "requirement": "Rechtliche, regulatorische und vertragliche Vorgaben mit Relevanz für die Informationssicherheit werden regelmäßig bestimmt.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.1-M2", + "policy": "R14", + "control": "7.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.1-M2", + "impl_anchor": "IMPL 7.1.1", + "condition": null, + "requirement": "Richtlinien zur Einhaltung der Vorgaben sind definiert, umgesetzt und den verantwortlichen Personen kommuniziert.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.1-S1", + "policy": "R14", + "control": "7.1.1", + "level": "should", + "type": "SOLL", + "is_isa": true, + "req_anchor": "REQ 7.1.1-S1", + "impl_anchor": "IMPL 7.1.1", + "condition": "FLAG_INCLUDE_SHOULD", + "requirement": "Die Integrität von Aufzeichnungen entsprechend rechtlichen, regulatorischen und vertraglichen Vorgaben sowie Geschäftsanforderungen wird berücksichtigt.", + "link": "{{LINK:R14#7.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.2-M1", + "policy": "R14", + "control": "7.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.2-M1", + "impl_anchor": "IMPL 7.1.2", + "condition": null, + "requirement": "Rechtliche und vertragliche Informationssicherheitsanforderungen an Verfahren und Prozesse bei der Verarbeitung personenbezogener Daten sind bestimmt.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.2-M2", + "policy": "R14", + "control": "7.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.2-M2", + "impl_anchor": "IMPL 7.1.2", + "condition": null, + "requirement": "Regelungen zur Einhaltung rechtlicher und vertraglicher Anforderungen an den Schutz personenbezogener Daten sind definiert und den beteiligten Personen bekannt.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "7.1.2-M3", + "policy": "R14", + "control": "7.1.2", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 7.1.2-M3", + "impl_anchor": "IMPL 7.1.2", + "condition": null, + "requirement": "Prozesse und Verfahren zum Schutz personenbezogener Daten sind im Informationssicherheits-Managementsystem berücksichtigt.", + "link": "{{LINK:R14#7.1.2}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-18" + ] + }, + { + "id": "8.1.1-M1", + "policy": "P01", + "control": "8.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 8.1.1-M1", + "impl_anchor": "REQ 8.1.1-M1", + "condition": "FLAG_PROTOTYPE_PROTECTION", + "requirement": "Bereiche, in denen Prototypen verarbeitet oder gelagert werden, sind durch definierte Sicherheitszonen und einen wirksamen Perimeter geschuetzt.", + "implementation": "Prototypenbereiche sind als eigene Sicherheitszone mit Zutrittskontrolle, Perimeterschutz und Protokollierung ausgewiesen.", + "link": "{{LINK:P01#8.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-20" + ] + }, + { + "id": "8.2.1-M1", + "policy": "P01", + "control": "8.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 8.2.1-M1", + "impl_anchor": "REQ 8.2.1-M1", + "condition": "FLAG_PROTOTYPE_PROTECTION", + "requirement": "Fuer Prototypen bestehen Geheimhaltungsverpflichtungen; die zugehoerigen Informationen sind klassifiziert und gekennzeichnet.", + "implementation": "Alle mit Prototypen befassten Personen unterzeichnen Geheimhaltungsvereinbarungen; Prototypen werden als vertraulich oder hoeher klassifiziert.", + "link": "{{LINK:P01#8.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "8.3.1-M1", + "policy": "P01", + "control": "8.3.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 8.3.1-M1", + "impl_anchor": "REQ 8.3.1-M1", + "condition": "FLAG_PROTOTYPE_PROTECTION", + "requirement": "Transport und Lagerung von Prototypen erfolgen nach dokumentierten Schutzvorgaben, die Vertraulichkeit und Integritaet sicherstellen.", + "implementation": "Transport und Lagerung folgen der Verfahrensanweisung VA-20: abgesicherte Behaeltnisse, protokollierte Uebergaben, Zutritts- und Sichtschutz.", + "link": "{{LINK:P01#8.3.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [ + "VA-20" + ] + }, + { + "id": "9.1.1-M1", + "policy": "D01", + "control": "9.1.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 9.1.1-M1", + "impl_anchor": "REQ 9.1.1-M1", + "condition": "FLAG_PERSONAL_DATA", + "requirement": "Verantwortlichkeiten fuer den Datenschutz sind benannt und die Datenschutz-Organisation ist dokumentiert.", + "implementation": "Die Rolle Datenschutzbeauftragte:r ist benannt und in die ISMS-Organisation eingebunden; Aufgaben und Meldewege sind dokumentiert.", + "link": "{{LINK:D01#9.1.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + }, + { + "id": "9.2.1-M1", + "policy": "D01", + "control": "9.2.1", + "level": "must", + "type": "MUSS", + "is_isa": true, + "req_anchor": "REQ 9.2.1-M1", + "impl_anchor": "REQ 9.2.1-M1", + "condition": "FLAG_PERSONAL_DATA", + "requirement": "Verarbeitungen personenbezogener Daten sind rechtmaessig, zweckgebunden und in einem Verzeichnis der Verarbeitungstaetigkeiten erfasst.", + "implementation": "Ein Verzeichnis der Verarbeitungstaetigkeiten wird gefuehrt; Rechtsgrundlage, Zweck und Loeschfristen sind je Verarbeitung dokumentiert.", + "link": "{{LINK:D01#9.2.1}}", + "nachweis_link": "{{LINK:NACHWEISREGISTER}}", + "verfahren": [] + } + ], + "verfahren": [ + { + "id": "VA-01", + "title": "Incident-Response- und Meldeverfahren", + "file": "verfahren/VA-01_Incident-Response-und-Meldeverfahren.md", + "policy": "R04", + "fulfills": [ + "1.6.1-M1", + "1.6.1-M2", + "1.6.2-M1", + "1.6.2-M2", + "1.6.2-S1", + "1.6.2-S2" + ], + "link": "{{LINK:VA-01}}" + }, + { + "id": "VA-02", + "title": "IT-Notfall- und Wiederanlaufverfahren (BCM)", + "file": "verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md", + "policy": "R04", + "fulfills": [ + "1.6.3-M1", + "1.6.3-S1", + "5.2.8-M1", + "5.2.8-S1" + ], + "link": "{{LINK:VA-02}}" + }, + { + "id": "VA-03", + "title": "Berechtigungsverfahren (Joiner/Mover/Leaver und Rezertifizierung)", + "file": "verfahren/VA-03_Berechtigungsverfahren.md", + "policy": "R08", + "fulfills": [ + "4.1.1-S1", + "4.1.3-M1", + "4.2.1-M1", + "4.2.1-M2", + "4.2.1-S1" + ], + "link": "{{LINK:VA-03}}" + }, + { + "id": "VA-04", + "title": "Change- und Patch-Management-Verfahren", + "file": "verfahren/VA-04_Change-und-Patch-Management-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.1-M1", + "5.2.5-M1" + ], + "link": "{{LINK:VA-04}}" + }, + { + "id": "VA-05", + "title": "Backup- und Restore-Verfahren", + "file": "verfahren/VA-05_Backup-und-Restore-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.9-M1", + "5.2.9-M2", + "5.2.9-S1" + ], + "link": "{{LINK:VA-05}}" + }, + { + "id": "VA-06", + "title": "Schwachstellenmanagement-Verfahren", + "file": "verfahren/VA-06_Schwachstellenmanagement-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.5-M1", + "5.2.5-S1", + "5.2.6-M1" + ], + "link": "{{LINK:VA-06}}" + }, + { + "id": "VA-07", + "title": "Kryptokonzept und Schlüsselverwaltung", + "file": "verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md", + "policy": "R09", + "fulfills": [ + "5.1.1-M1", + "5.1.1-M2", + "5.1.1-S1", + "5.1.2-M1", + "5.1.2-S1" + ], + "link": "{{LINK:VA-07}}" + }, + { + "id": "VA-08", + "title": "Asset- und Klassifizierungsverfahren", + "file": "verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md", + "policy": "R02", + "fulfills": [ + "1.3.1-M1", + "1.3.1-M2", + "1.3.1-S1", + "1.3.2-M1", + "1.3.2-M2", + "1.3.2-S1" + ], + "link": "{{LINK:VA-08}}" + }, + { + "id": "VA-09", + "title": "Risikomanagement-Verfahren", + "file": "verfahren/VA-09_Risikomanagement-Verfahren.md", + "policy": "R03", + "fulfills": [ + "1.4.1-M1", + "1.4.1-M2", + "1.4.1-M3", + "1.4.1-S1" + ], + "link": "{{LINK:VA-09}}" + }, + { + "id": "VA-10", + "title": "Lieferanten-Onboarding- und Bewertungsverfahren", + "file": "verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md", + "policy": "R13", + "fulfills": [ + "6.1.1-M1", + "6.1.1-M2", + "6.1.1-S1", + "6.1.2-M1", + "6.1.2-S1", + "6.1.3-M1" + ], + "link": "{{LINK:VA-10}}" + }, + { + "id": "VA-11", + "title": "Cloud- und KI-Freigabeverfahren", + "file": "verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md", + "policy": "R12", + "fulfills": [ + "5.3.4-M1", + "5.3.4-M2", + "5.3.4-S1", + "5.3.4-KI-M1", + "5.3.4-KI-M2", + "5.3.4-KI-M3", + "5.3.4-KI-S1" + ], + "link": "{{LINK:VA-11}}" + }, + { + "id": "VA-12", + "title": "Awareness- und Schulungsverfahren", + "file": "verfahren/VA-12_Awareness-und-Schulungsverfahren.md", + "policy": "R05", + "fulfills": [ + "2.1.3-M1", + "2.1.3-S1" + ], + "link": "{{LINK:VA-12}}" + }, + { + "id": "VA-13", + "title": "Logging- und Monitoring-Verfahren", + "file": "verfahren/VA-13_Logging-und-Monitoring-Verfahren.md", + "policy": "R10", + "fulfills": [ + "5.2.4-M1", + "5.2.4-S1" + ], + "link": "{{LINK:VA-13}}" + }, + { + "id": "VA-14", + "title": "Personalsicherheit – Eignungsprüfung & sensible Tätigkeiten", + "file": "verfahren/VA-14_Personalsicherheit-Eignungspruefung.md", + "policy": "R05", + "fulfills": [ + "2.1.1-M1", + "2.1.1-M2", + "2.1.1-M3", + "2.1.1-S1", + "2.1.1-S2", + "2.1.2-M1", + "2.1.2-M2", + "2.1.2-S1", + "2.1.2-S2", + "2.1.2-S3" + ], + "link": "{{LINK:VA-14}}" + }, + { + "id": "VA-15", + "title": "Interne Audits & Complianceprüfungen", + "file": "verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md", + "policy": "R03", + "fulfills": [ + "1.5.1-M1", + "1.5.1-M2", + "1.5.1-M3", + "1.5.1-M4", + "1.5.1-M5", + "1.5.1-S1", + "1.5.2-M1", + "1.5.2-M2", + "1.5.2-S1" + ], + "link": "{{LINK:VA-15}}" + }, + { + "id": "VA-16", + "title": "Sichere Beschaffung, Entwicklung & Abnahme", + "file": "verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md", + "policy": "R11", + "fulfills": [ + "5.3.1-M1", + "5.3.1-M2", + "5.3.1-M3", + "5.3.1-M4", + "5.3.1-S1", + "5.3.1-S2", + "5.3.1-S3", + "5.3.1-S4", + "5.3.1-S5", + "5.3.1-V1", + "5.3.2-M1", + "5.3.2-S1", + "5.3.2-S2", + "5.3.2-S3", + "5.3.2-H1" + ], + "link": "{{LINK:VA-16}}" + }, + { + "id": "VA-17", + "title": "Zutritts- & Besuchermanagement (physisch)", + "file": "verfahren/VA-17_Zutritts-und-Besuchermanagement.md", + "policy": "R07", + "fulfills": [ + "3.1.1-S1", + "3.1.1-S2", + "3.1.1-S3", + "3.1.1-S4", + "3.1.1-S5" + ], + "link": "{{LINK:VA-17}}" + }, + { + "id": "VA-18", + "title": "Datenschutz- & Compliance-Pflege", + "file": "verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md", + "policy": "R14", + "fulfills": [ + "7.1.1-M1", + "7.1.1-M2", + "7.1.1-S1", + "7.1.2-M1", + "7.1.2-M2", + "7.1.2-M3" + ], + "link": "{{LINK:VA-18}}" + }, + { + "id": "VA-19", + "title": "Informationssicherheit in Projekten", + "file": "verfahren/VA-19_Informationssicherheit-in-Projekten.md", + "policy": "R01", + "fulfills": [ + "1.2.3-M1", + "1.2.3-S1", + "1.2.3-S2", + "1.2.3-S3", + "1.2.3-H1" + ], + "link": "{{LINK:VA-19}}" + }, + { + "id": "VA-20", + "title": "Prototypen-Zutritt und -Transport", + "file": "verfahren/VA-20_Prototypen-Zutritt-und-Transport.md", + "policy": "P01", + "fulfills": [ + "8.1.1-M1", + "8.3.1-M1" + ], + "link": "{{LINK:VA-20}}" + } + ] +} \ No newline at end of file diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/D01_Datenschutz.md b/seed/isms-vorlagenpaket-v2/richtlinien/D01_Datenschutz.md new file mode 100644 index 0000000..9df140a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/D01_Datenschutz.md @@ -0,0 +1,49 @@ +# Richtlinie Datenschutz + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_DPO}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt den Schutz personenbezogener Daten (Prüfziel Datenschutz, VDA ISA Kapitel 9). Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und ergänzt die Richtlinie Compliance und Datenschutz ({{LINK:R14}}). + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}), soweit personenbezogene Daten verarbeitet werden. + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA, Kapitel 9) und **Umsetzung bei {{ORG_NAME}}**. + +{{#if FLAG_PERSONAL_DATA}} +### 3.1 Datenschutz-Organisation (ISA 9.1.1) + +**Anforderung** + + +- **[MUSS]** Verantwortlichkeiten für den Datenschutz sind benannt und die Datenschutz-Organisation ist dokumentiert. + +**Umsetzung bei {{ORG_NAME}}** + +Die Rolle {{ROLE_DPO}} ist benannt und in die ISMS-Organisation eingebunden. Aufgaben, Meldewege und Eskalation sind dokumentiert. + +### 3.2 Rechtmäßigkeit und Verarbeitungsverzeichnis (ISA 9.2.1) + +**Anforderung** + + +- **[MUSS]** Verarbeitungen personenbezogener Daten sind rechtmäßig, zweckgebunden und in einem Verzeichnis der Verarbeitungstätigkeiten erfasst. + +**Umsetzung bei {{ORG_NAME}}** + +Ein Verzeichnis der Verarbeitungstätigkeiten wird geführt und regelmäßig aktualisiert. Für jede Verarbeitung sind Rechtsgrundlage, Zweck und Löschfristen dokumentiert. +{{/if}} diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/L00_Informationssicherheitsleitlinie.md b/seed/isms-vorlagenpaket-v2/richtlinien/L00_Informationssicherheitsleitlinie.md new file mode 100644 index 0000000..5f8fb67 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/L00_Informationssicherheitsleitlinie.md @@ -0,0 +1,175 @@ +# Informationssicherheitsleitlinie + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Leitlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + +## 1. Zweck + + +Diese Informationssicherheitsleitlinie beschreibt die grundsätzlichen Anforderungen, Ziele und Verantwortlichkeiten der {{ORG_NAME}} zum Schutz von Informationen, IT-Systemen, Geschäftsprozessen und unterstützenden Werten. Die Anforderungen der Informationssicherheit sind bestimmt, dokumentiert und an den Zielen der {{ORG_NAME}} ausgerichtet. + +Ziel ist es, ein angemessenes Informationssicherheitsniveau sicherzustellen und die Anforderungen des VDA ISA 2027 im Bereich Informationssicherheit zu erfüllen. + +## 2. Geltungsbereich + +Diese Leitlinie gilt für den definierten ISMS-Geltungsbereich: + +{{ISMS_SCOPE_DESCRIPTION}} + +Sie gilt für: + +- alle Mitarbeitenden innerhalb des Geltungsbereichs, +- Führungskräfte, +- externe Dienstleister, soweit diese Zugriff auf Informationen, Systeme oder Prozesse der Organisation haben, +- relevante IT-Systeme, Informationen, Anwendungen, Standorte und Geschäftsprozesse innerhalb des ISMS-Scopes. + +## 3. Ziele der Informationssicherheit + + +Die Leitlinie benennt die Ziele und die Bedeutung der Informationssicherheit. Die Organisation verfolgt mit dem ISMS insbesondere folgende Ziele: + +- Schutz vertraulicher Informationen vor unbefugtem Zugriff, +- Sicherstellung der Integrität von Informationen und Systemen, +- Sicherstellung der Verfügbarkeit geschäftskritischer Informationen, Systeme und Services, +- Einhaltung gesetzlicher, regulatorischer und vertraglicher Anforderungen, +- angemessener Schutz von Kundeninformationen, personenbezogenen Daten, Geschäftsgeheimnissen und weiteren schutzbedürftigen Informationen, +- strukturierte Erkennung, Bewertung und Behandlung von Informationssicherheitsrisiken, +- kontinuierliche Verbesserung der Informationssicherheit. + +## 4. Grundsätze der Informationssicherheit + +Die Informationssicherheit basiert auf folgenden Grundsätzen: + +### 4.1 Risikoorientierung +Informationssicherheitsmaßnahmen werden risikoorientiert geplant, umgesetzt, überprüft und verbessert. Risiken werden im eingesetzten ISMS-Tool ({{TOOL_NAME}}) bewertet und nachverfolgt (siehe {{LINK:R03}}). + +### 4.2 Angemessenheit +Schutzmaßnahmen müssen dem Schutzbedarf der Informationen, Systeme und Prozesse angemessen sein. Dabei werden Vertraulichkeit, Integrität und Verfügbarkeit berücksichtigt. + +### 4.3 Verantwortung +Informationssicherheit ist eine gemeinsame Verantwortung aller Mitarbeitenden. Die {{ROLE_MANAGEMENT}} trägt die Gesamtverantwortung für das ISMS. + +### 4.4 Nachvollziehbarkeit +Entscheidungen, Bewertungen, Freigaben und wesentliche Maßnahmen im Zusammenhang mit Informationssicherheit sind nachvollziehbar zu dokumentieren. + +### 4.5 Kontinuierliche Verbesserung +Das ISMS wird regelmäßig überprüft und bei Bedarf angepasst. Erkenntnisse aus Audits, Vorfällen, Risiken, Änderungen und Managementbewertungen fließen in die Verbesserung ein. + +## 5. Informationssicherheitsanforderungen + + +{{#if FLAG_INCLUDE_SHOULD}}Die Informationssicherheitsanforderungen basieren auf der Strategie der {{ORG_NAME}}; gesetzliche und vertragliche Vorgaben werden berücksichtigt. {{/if}}Die Organisation bestimmt und dokumentiert Informationssicherheitsanforderungen auf Basis von: + +- gesetzlichen und regulatorischen Anforderungen, +- vertraglichen Anforderungen, insbesondere von Kunden und Partnern, +- Anforderungen aus dem VDA ISA, +- internen Geschäftsanforderungen, +- Ergebnissen aus Risikoanalysen, +- Schutzbedarf von Informationen, Prozessen und IT-Systemen, +- Anforderungen aus Projekten, Änderungen und externen IT-Services. + +Die jeweils relevanten Anforderungen werden im ISMS berücksichtigt und über geeignete Richtlinien, Prozesse, technische Maßnahmen und Nachweise umgesetzt. + +## 6. Rollen und Verantwortlichkeiten + +Die Organisation definiert Rollen und Verantwortlichkeiten für Informationssicherheit. Dazu gehören mindestens: + +| Rolle | Grundsätzliche Verantwortung | +|-------|------------------------------| +| {{ROLE_MANAGEMENT}} | Gesamtverantwortung, Freigabe der Informationssicherheitsleitlinie, Bereitstellung angemessener Ressourcen | +| {{ROLE_ISB}} | Steuerung, Pflege und Weiterentwicklung des ISMS | +| Führungskräfte | Umsetzung der Anforderungen im jeweiligen Verantwortungsbereich | +| {{ROLE_IT_LEAD}} | Umsetzung technischer und organisatorischer Sicherheitsmaßnahmen im IT-Bereich | +| Asset Owner / Prozessverantwortliche | Bewertung und Pflege relevanter Informationen, Prozesse und Assets im ISMS-Tool | +| Mitarbeitende | Einhaltung der Richtlinien und Meldung von Sicherheitsereignissen | +| Externe Dienstleister | Einhaltung vertraglich vereinbarter Sicherheitsanforderungen | + +Die konkrete Rollen- und Verantwortlichkeitszuordnung wird im ISMS-Tool ({{TOOL_NAME}}) oder in einer ergänzenden Rollenmatrix gepflegt (siehe auch {{LINK:R01}}). + +## 7. Verbindlichkeit + + + +Diese Leitlinie ist durch die {{ROLE_MANAGEMENT}} genehmigt und für alle betroffenen Personen im Geltungsbereich verbindlich. {{#if FLAG_INCLUDE_SHOULD}}Verstöße gegen Informationssicherheitsanforderungen können zu organisatorischen, arbeitsrechtlichen oder vertraglichen Maßnahmen führen. {{/if}}Alle Mitarbeitenden sind verpflichtet: + +- die geltenden Informationssicherheitsrichtlinien einzuhalten, +- schutzbedürftige Informationen angemessen zu behandeln, +- Sicherheitsereignisse oder Verdachtsfälle unverzüglich zu melden, +- nur freigegebene Systeme, Anwendungen und Dienste zu nutzen, +- erkannte Schwachstellen oder Risiken an die zuständige Stelle zu melden. + +## 8. Veröffentlichung und Kommunikation + + + +Die Informationssicherheitsleitlinie wird den relevanten Personen in geeigneter Form bekannt gemacht; über relevante Änderungen werden Mitarbeitende und betroffene externe Partner informiert. Dies kann erfolgen über: + +- Veröffentlichung im ISMS-Tool ({{TOOL_NAME}}), +- internes Wiki oder Dokumentenmanagementsystem, +- Onboarding-Prozess, +- Awareness-Schulungen (siehe {{LINK:R05}}), +- direkte Kommunikation an betroffene Zielgruppen. + +## 9. Überprüfung und Aktualisierung + + +Diese Leitlinie wird regelmäßig überprüft, mindestens jedoch: + +- {{REVIEW_CYCLE}}, +- bei wesentlichen Änderungen des ISMS-Geltungsbereichs, +- bei wesentlichen organisatorischen oder technischen Änderungen, +- bei relevanten Sicherheitsvorfällen, +- bei neuen oder geänderten regulatorischen, gesetzlichen oder vertraglichen Anforderungen. + +Änderungen werden dokumentiert und durch die {{ROLE_MANAGEMENT}} genehmigt. + +## 10. Nachweise + +Die Nachweise zur Umsetzung dieser Leitlinie werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 11. Verwandte Dokumente + + +Weitere themenspezifische Sicherheitsrichtlinien (R01–R14) sind etabliert und aufeinander abgestimmt. + +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- ISMS-Organisation und Rollen: {{LINK:R01}} +- Alle thematischen Richtlinien: {{LINK:R01}} … {{LINK:R14}} + + + + +{{#if FLAG_FW_ISO27001}} + +## Anhang A — Informationssicherheitspolitik, Ziele und Kommunikation + +*Anforderungsbezug:* ISO/IEC 27001 5.2, 6.2, 7.4, A.5.1 + +**Anforderung** + + +- **[ISO 5.2]** Die oberste Leitung hat eine Informationssicherheitspolitik festzulegen, die zum Zweck der Organisation passt und Ziele bzw. einen Rahmen dafür enthält. + +- **[ISO 6.2]** Informationssicherheitsziele sind für relevante Funktionen und Ebenen festzulegen und deren Erreichung zu planen. + +- **[ISO 7.4]** Die für das ISMS relevante interne und externe Kommunikation ist zu bestimmen. + +- **[ISO A.5.1]** Ein Satz von Informationssicherheitsrichtlinien ist zu definieren, von der Leitung zu genehmigen, zu veröffentlichen, zu kommunizieren und regelmäßig sowie anlassbezogen zu überprüfen. + +**Umsetzung bei {{ORG_NAME}}** + + +Diese Leitlinie wird von der {{ROLE_MANAGEMENT}} freigegeben, im {{TOOL_NAME}} veröffentlicht und allen Beschäftigten sowie relevanten Dritten bekannt gemacht; die Kenntnisnahme wird je Fassung dokumentiert. Die Überprüfung erfolgt mindestens {{POLICY_REVIEW_CYCLE}} sowie bei wesentlichen Änderungen (BL-GOV-03). Die themenspezifischen Richtlinien und die Verfahrensanweisungen konkretisieren sie und durchlaufen denselben Freigabe- und Prüfzyklus. Die Informationssicherheitsziele sind messbar formuliert und mit Zielwert, verantwortlicher Rolle und Termin im {{TOOL_NAME}} hinterlegt; ihre Erreichung wird {{MGMT_REVIEW_CYCLE}} bewertet. Für die interne und externe Kommunikation zur Informationssicherheit ist festgelegt, worüber, wann, mit wem und durch wen kommuniziert wird; zentraler Ansprechpartner ist {{ROLE_ISB}}. + +{{/if}} + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/P01_Prototypenschutz.md b/seed/isms-vorlagenpaket-v2/richtlinien/P01_Prototypenschutz.md new file mode 100644 index 0000000..9216aa5 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/P01_Prototypenschutz.md @@ -0,0 +1,60 @@ +# Richtlinie Prototypenschutz + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt den Schutz von Prototypen und schutzbedürftigen Entwicklungsobjekten (Prüfziel Prototypenschutz, VDA ISA Kapitel 8). Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und wird durch das Verfahren {{LINK:VA-20}} operationalisiert. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}), soweit Prototypen bzw. schutzbedürftige Entwicklungsobjekte verarbeitet, gelagert oder transportiert werden. + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA, Kapitel 8) und **Umsetzung bei {{ORG_NAME}}**. + +{{#if FLAG_PROTOTYPE_PROTECTION}} +### 3.1 Physische Sicherheit und Perimeter (ISA 8.1.1) + +**Anforderung** + + +- **[MUSS]** Bereiche, in denen Prototypen verarbeitet oder gelagert werden, sind durch definierte Sicherheitszonen und einen wirksamen Perimeter geschützt. + +**Umsetzung bei {{ORG_NAME}}** + +Prototypenbereiche sind als eigene Sicherheitszone mit Zutrittskontrolle, Perimeterschutz und Protokollierung ausgewiesen. Der Zutritt ist auf berechtigte Personen beschränkt. + +### 3.2 Geheimhaltung und Klassifizierung (ISA 8.2.1) + +**Anforderung** + + +- **[MUSS]** Für Prototypen bestehen Geheimhaltungsverpflichtungen; die zugehörigen Informationen sind klassifiziert und entsprechend gekennzeichnet. + +**Umsetzung bei {{ORG_NAME}}** + +Alle mit Prototypen befassten Personen (intern und extern) unterzeichnen Geheimhaltungsvereinbarungen. Prototypen und zugehörige Unterlagen werden gemäß Klassifizierungsschema als vertraulich oder höher eingestuft. + +### 3.3 Transport und Lagerung (ISA 8.3.1) + +**Anforderung** + + +- **[MUSS]** Transport und Lagerung von Prototypen erfolgen nach dokumentierten Schutzvorgaben, die Vertraulichkeit und Integrität sicherstellen. + +**Umsetzung bei {{ORG_NAME}}** + +Transport und Lagerung folgen dem Verfahren {{LINK:VA-20}}: abgesicherte Behältnisse, protokollierte Übergaben, Zutritts- und Sichtschutz sowie Nachverfolgbarkeit. +{{/if}} diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R01_ISMS-Organisation-und-Rollen.md b/seed/isms-vorlagenpaket-v2/richtlinien/R01_ISMS-Organisation-und-Rollen.md new file mode 100644 index 0000000..1a3294d --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R01_ISMS-Organisation-und-Rollen.md @@ -0,0 +1,294 @@ +# Richtlinie ISMS-Organisation und Rollen + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Aufbau, Steuerung und Verantwortlichkeiten des ISMS der {{ORG_NAME}} sowie die Berücksichtigung der Informationssicherheit in Projekten. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Steuerung der Informationssicherheit + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.2.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 5.1, A.5.4{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Der Geltungsbereich des ISMS (die durch das ISMS gesteuerte Organisation) ist definiert. + +- **[MUSS]** Die Anforderungen der Organisation an das ISMS sind bestimmt. + +- **[MUSS]** Die Organisationsleitung hat das ISMS beauftragt und genehmigt. + +- **[MUSS]** Das ISMS stellt der Organisationsleitung geeignete Mittel zur Überwachung und Steuerung bereit (z. B. Managementbewertung). + +- **[MUSS]** Die anwendbaren Controls sind bestimmt (z. B. ISO-27001-Anwendbarkeitserklärung oder ausgefüllter ISA-Katalog). + +- **[MUSS]** Die Wirksamkeit des ISMS wird regelmäßig durch die Leitung überprüft. +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO 5.1]** Die oberste Leitung hat Führung und Verpflichtung in Bezug auf das ISMS nachzuweisen. + +- **[ISO A.5.4]** Die Leitung hat von allen Beschäftigten die Anwendung der Informationssicherheit gemäß den festgelegten Vorgaben einzufordern. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Der ISMS-Geltungsbereich, die Anforderungen und die anwendbaren Controls (Anwendbarkeitserklärung/ISA-Katalog) sind im ISMS-Tool ({{TOOL_NAME}}) dokumentiert. Die {{ROLE_MANAGEMENT}} hat das ISMS per Managementbeschluss beauftragt und genehmigt, stellt Ressourcen bereit und überprüft die Wirksamkeit mindestens {{REVIEW_CYCLE}} in einer dokumentierten Managementbewertung; die operative Steuerung liegt bei {{ROLE_ISB}}. + +### 3.2 Organisation der Informationssicherheit + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.2.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 5.3, 7.1, A.5.2, A.5.3{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Verantwortlichkeiten für Informationssicherheit sind definiert, dokumentiert und zugewiesen. + +- **[MUSS]** Die verantwortlichen Beschäftigten sind definiert, qualifiziert und für ihre Aufgabe befähigt. + +- **[MUSS]** Die erforderlichen Ressourcen stehen zur Verfügung. + +- **[MUSS]** Die Ansprechpartner sind innerhalb der Organisation und relevanten Geschäftspartnern bekannt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Es besteht eine Definition und Dokumentation einer angemessenen Informationssicherheitsstruktur innerhalb der Organisation. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Sicherheitsrelevante Rollen, die nicht Teil des ISMS, aber für die Informationssicherheit relevant sind, werden berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Eine angemessene organisatorische Trennung von Verantwortlichkeiten ist etabliert, um Interessenkonflikte zu vermeiden (Funktionstrennung). (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO 5.3]** Verantwortlichkeiten und Befugnisse für sicherheitsrelevante Rollen sind zuzuweisen und bekannt zu machen. + +- **[ISO 7.1]** Die für das ISMS erforderlichen Ressourcen sind zu bestimmen und bereitzustellen. + +- **[ISO A.5.2]** Rollen und Verantwortlichkeiten für die Informationssicherheit sind zu definieren und zuzuweisen. + +- **[ISO A.5.3]** Widerstreitende Aufgaben und Verantwortungsbereiche sind zu trennen, um unbefugte oder unbeabsichtigte Änderungen und Missbrauch zu reduzieren. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Die Verantwortlichkeiten sind in der Rollen-/Verantwortungsmatrix und im ISMS-Tool ({{TOOL_NAME}}) dokumentiert und den Rolleninhabern sowie relevanten Geschäftspartnern bekannt gemacht. Die Rolle {{ROLE_ISB}} ist benannt, qualifiziert, mit Ressourcen und Weisungsrechten ausgestattet und berichtet direkt an die {{ROLE_MANAGEMENT}}. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf ist eine organisatorische Funktionstrennung (z. B. Umsetzung vs. Kontrolle) etabliert; unvermeidbare Doppelrollen werden durch kompensierende Kontrollen (Vier-Augen-Prinzip) abgesichert. +{{/if}} + +### 3.3 Informationssicherheit in Projekten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.2.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.8{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Projekte werden unter Berücksichtigung der Informationssicherheitsanforderungen klassifiziert. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Verfahren und Kriterien für die Klassifizierung von Projekten sind dokumentiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** In einer frühen Projektphase wird eine Risikobewertung nach dem definierten Verfahren durchgeführt und bei Projektänderungen wiederholt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Für identifizierte Informationssicherheitsrisiken werden Maßnahmen abgeleitet und im Projekt berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die abgeleiteten Maßnahmen werden während des Projekts regelmäßig überprüft und bei Änderungen der Bewertungskriterien neu bewertet. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.8]** Informationssicherheit ist in das Projektmanagement zu integrieren. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Projekte werden zu Beginn anhand des dokumentierten Kriterienkatalogs (BL-PROJ-01) hinsichtlich Informationssicherheitsbedarf klassifiziert; Einstufung, Risikobewertung und abgeleitete Maßnahmen werden im Projektregister ({{LINK:REG-PROJECTS}}) geführt. In einer frühen Projektphase und bei Änderungen erfolgt eine Risikobewertung nach dem Verfahren Informationssicherheit in Projekten ({{LINK:VA-19}}); Maßnahmen werden als Aufgaben im {{TOOL_TICKET}} nachgehalten und vor Projektabschluss geprüft. Verantwortlich ist die Projektleitung; bei erhöhtem Schutzbedarf wird {{ROLE_ISB}} eingebunden. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf werden die abgeleiteten Maßnahmen fortlaufend im Projektverlauf überprüft und bei geänderten Bewertungskriterien neu bewertet. +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.4 Kontext, interessierte Parteien und Anwendungsbereich des ISMS + +*Anforderungsbezug:* ISO/IEC 27001 4.1, 4.2, 4.3, 4.4 + +**Anforderung** + + +- **[ISO 4.1]** Interne und externe Themen, die die Fähigkeit zur Erreichung der ISMS-Ziele beeinflussen, sind zu bestimmen und aktuell zu halten. + +- **[ISO 4.2]** Die für das ISMS relevanten interessierten Parteien und deren Anforderungen an die Informationssicherheit sind zu ermitteln. + +- **[ISO 4.3]** Der Anwendungsbereich des ISMS ist unter Berücksichtigung der Themen, Anforderungen und Schnittstellen festzulegen und als dokumentierte Information zu führen. + +- **[ISO 4.4]** Ein ISMS ist einzurichten, umzusetzen, aufrechtzuerhalten und fortlaufend zu verbessern. + +**Umsetzung bei {{ORG_NAME}}** + + +Interne und externe Themen sowie die relevanten interessierten Parteien und deren Anforderungen werden im {{TOOL_NAME}} als Kontext- und Stakeholderanalyse geführt und mindestens {{POLICY_REVIEW_CYCLE}} sowie bei wesentlichen Änderungen aktualisiert. Der Anwendungsbereich des ISMS ({{ISMS_SCOPE}}) ist als dokumentierte Information festgelegt und benennt Standorte, Prozesse, Organisationseinheiten und IT-Dienste sowie Schnittstellen und Abhängigkeiten zu Dritten; Ausschlüsse werden begründet. Das ISMS wird nach dem PDCA-Zyklus betrieben und fortlaufend verbessert. Verantwortlich: {{ROLE_ISB}}; Freigabe: {{ROLE_MANAGEMENT}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.5 Planung von Änderungen am ISMS + +*Anforderungsbezug:* ISO/IEC 27001 6.3 + +**Anforderung** + + +- **[ISO 6.3]** Änderungen am ISMS sind geplant durchzuführen. + +**Umsetzung bei {{ORG_NAME}}** + + +Änderungen am ISMS — Anwendungsbereich, Organisation, Rollen, wesentliche Prozesse oder Systeme — werden geplant, vor der Umsetzung bewertet und im {{TOOL_NAME}} dokumentiert. Die Bewertung umfasst Zweck und mögliche Folgen der Änderung, Auswirkungen auf Risiken und Maßnahmen, benötigte Ressourcen sowie die Zuweisung von Verantwortlichkeiten. Die Freigabe erfolgt durch {{ROLE_MANAGEMENT}}; technische Änderungen laufen zusätzlich über das Änderungsmanagement (BL-OPS-09, siehe {{LINK:VA-04}}). + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.6 Lenkung dokumentierter Information + +*Anforderungsbezug:* ISO/IEC 27001 7.5.1, 7.5.2, 7.5.3 + +**Anforderung** + + +- **[ISO 7.5.1]** Das ISMS muss die von der Norm geforderte und die als notwendig bestimmte dokumentierte Information enthalten. + +- **[ISO 7.5.2]** Bei Erstellung und Aktualisierung dokumentierter Information sind Kennzeichnung, Format/Medium und Prüfung/Freigabe sicherzustellen. + +- **[ISO 7.5.3]** Dokumentierte Information ist zu lenken (Verfügbarkeit, Schutz, Verteilung, Zugriff, Aufbewahrung, Änderungssteuerung). + +**Umsetzung bei {{ORG_NAME}}** + + +Die dokumentierte Information des ISMS wird im {{TOOL_NAME}} geführt. Jedes Dokument trägt Titel, eindeutige Kennung, Version, Datum, Status, verantwortliche Rolle und Freigebenden; Erstellung und Änderung durchlaufen Prüfung und Freigabe im Vier-Augen-Prinzip (BL-GOV-03). Die Lenkung stellt Verfügbarkeit für die berechtigten Rollen, Schutz vor unbefugter Änderung, gesteuerte Verteilung, Versionsführung mit Änderungsverlauf und die Aufbewahrung abgelöster Fassungen ({{RECORDS_RETENTION}}) sicher. Dokumente externer Herkunft werden gekennzeichnet und ebenso gelenkt. Der Prüfzyklus beträgt {{POLICY_REVIEW_CYCLE}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.7 Kontakte zu Behörden und Interessengruppen + +*Anforderungsbezug:* ISO/IEC 27001 A.5.5, A.5.6 + +**Anforderung** + + +- **[ISO A.5.5]** Angemessene Kontakte zu relevanten Behörden sind einzurichten und zu pflegen. + +- **[ISO A.5.6]** Angemessene Kontakte zu speziellen Interessengruppen, Fachforen und Sicherheitsverbänden sind zu pflegen. + +**Umsetzung bei {{ORG_NAME}}** + + +{{ROLE_ISB}} pflegt eine Kontaktliste der relevanten Behörden und Meldestellen ({{AUTHORITY_CONTACTS}}) mit Zuständigkeit, Erreichbarkeit und Meldeweg; sie wird {{POLICY_REVIEW_CYCLE}} auf Aktualität geprüft und ist im Notfall auch ohne IT-Zugriff verfügbar. Meldepflichten und Fristen sind im Incident-Verfahren hinterlegt ({{LINK:VA-01}}). Zusätzlich werden fachliche Kontakte zu Interessengruppen, Fachforen und Sicherheitsverbänden gepflegt; die daraus gewonnenen Erkenntnisse fließen in die Bewertung von Bedrohungsinformationen ein. + +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_MANAGEMENT}} | Beauftragung, Gesamtverantwortung, Managementbewertung | +| {{ROLE_ISB}} | Operative Steuerung des ISMS | +| {{ROLE_IT_LEAD}} | Technische Umsetzung | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:L00}}, {{LINK:R03}}, {{LINK:R13}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md b/seed/isms-vorlagenpaket-v2/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md new file mode 100644 index 0000000..35a0ba4 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R02_Asset-und-Klassifizierungsrichtlinie.md @@ -0,0 +1,259 @@ +# Richtlinie Asset- und Klassifizierungsrichtlinie + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Identifikation, Klassifizierung und geschützten Umgang mit Informationswerten sowie die Zulassung von Hard- und Software. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Identifikation von Informationswerten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.9{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Informationswerte und weitere sicherheitsrelevante Assets der Organisation sind identifiziert und erfasst. + +- **[MUSS]** Die unterstützenden Assets, die die Informationswerte verarbeiten, sind identifiziert und erfasst. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Katalog der relevanten Informationswerte existiert; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.9]** Ein Inventar der Informationen und zugehörigen Assets einschließlich Eigentümer ist zu erstellen und zu pflegen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Informationswerte und unterstützende Assets werden im ISMS-Tool ({{TOOL_NAME}}) im Asset-Inventar mit Attributen (Owner, Standort, Schutzbedarf) erfasst und als Katalog gepflegt (siehe {{LINK:VA-08}}); Zu-/Abgänge werden über das {{TOOL_TICKET}} ausgelöst. + +### 3.2 Klassifizierung von Informationswerten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.12, A.5.13{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Ein konsistentes Schema zur Klassifizierung von Informationswerten hinsichtlich des Schutzziels Vertraulichkeit ist vorhanden. + +- **[MUSS]** Die Bewertung der identifizierten Informationswerte erfolgt nach den definierten Kriterien und wird dem Klassifizierungsschema zugeordnet. + +- **[MUSS]** Vorgaben zur Handhabung unterstützender Assets (z. B. Kennzeichnung, Nutzung, Transport, Speicherung, Rückgabe, Löschung/Vernichtung) abhängig von der Klassifizierung sind vorhanden und umgesetzt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Schutzziele Integrität und Verfügbarkeit werden berücksichtigt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.12]** Informationen sind entsprechend ihrem Schutzbedarf (Vertraulichkeit, Integrität, Verfügbarkeit) zu klassifizieren. + +- **[ISO A.5.13]** Verfahren zur Kennzeichnung von Informationen gemäß dem Klassifizierungsschema sind zu entwickeln und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Es gilt ein konsistentes vierstufiges Klassifizierungsschema (Öffentlich / Intern / Vertraulich / Streng vertraulich) für Vertraulichkeit; die Einstufung erfolgt nach definierten Kriterien durch den Asset Owner im ISMS-Tool und berücksichtigt auch Integrität und Verfügbarkeit. Handhabungsvorgaben je Schutzklasse (Kennzeichnung, Speicherung, Transport, Übertragung BL-CRY-01/04, Löschung BL-DEL-01) sind definiert, umgesetzt und bekannt gemacht (siehe {{LINK:VA-08}}). + +### 3.3 Nutzung freigegebener externer IT-Dienste/Hardware + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.10{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Externe IT-Dienste werden nicht ohne ausdrückliche Bewertung und Umsetzung der Informationssicherheitsanforderungen genutzt; dabei werden die einschlägigen Aspekte berücksichtigt. + +- **[MUSS]** Die externen IT-Dienste sind mit dem Schutzbedarf der verarbeiteten Informationswerte abgestimmt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Anforderungen an Beschaffung, Inbetriebnahme und Freigabe im Zusammenhang mit der Nutzung externer IT-Dienste sind bestimmt und erfüllt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Verfahren zur Freigabe unter Berücksichtigung des Schutzbedarfs ist etabliert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Externe IT-Dienste und ihre Freigabe sind dokumentiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Es wird regelmäßig überprüft, dass nur freigegebene externe IT-Dienste genutzt werden. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.10]** Regeln zur zulässigen Nutzung und zum Umgang mit Informationen und Assets sind festzulegen, zu dokumentieren und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Externe IT-Dienste/-Komponenten werden vor Nutzung bewertet, mit dem Schutzbedarf abgestimmt und über ein definiertes Verfahren freigegeben; die Freigaben werden im Register externe IT-/Cloud-/KI-Dienste ({{LINK:REG-EXT-SERVICES}}) geführt (Lieferant {{LINK:VA-10}}, Asset {{LINK:VA-08}}) und regelmäßig auf ausschließliche Nutzung freigegebener Dienste geprüft. + +### 3.4 Freigabe von Software + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.3.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.19{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Software wird vor Installation oder Nutzung freigegeben; dabei werden die einschlägigen Aspekte berücksichtigt. + +- **[MUSS]** Die Softwarefreigabe gilt auch für Spezialsoftware wie Wartungswerkzeuge. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die zu verwaltenden Softwarearten (Firmware, Betriebssysteme, Anwendungen, Bibliotheken, Gerätetreiber) sind bestimmt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Repositorys der verwalteten Software existieren. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Software-Repositorys sind gegen unbefugte Manipulation geschützt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Freigabe von Software wird regelmäßig überprüft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Softwareversionen und Patch-Stände sind bekannt. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Zusätzliche Anforderungen an die Softwarenutzung (z. B. Kontroll-/Überwachungsbedarf der Nutzung) sind, sofern vorhanden, bestimmt. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.19]** Verfahren und Maßnahmen zur sicheren Verwaltung der Softwareinstallation auf Produktivsystemen sind umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Software (inkl. Spezial-/Wartungssoftware) wird vor Einsatz freigegeben; zugelassene Software wird im Register Software-Whitelist ({{LINK:REG-SW-WHITELIST}}) mit Version/Patch-Stand, Quelle/Lieferant ({{LINK:VA-10}}) und Freigabestatus geführt und ist mit dem Asset-Inventar ({{LINK:VA-08}}) verknüpft; Beschaffung/Freigabe läuft über das {{TOOL_TICKET}}. Verwaltete Softwarearten sind bestimmt, Repositorys gegen Manipulation geschützt und Freigaben werden regelmäßig überprüft. + +{{#if FLAG_ELEVATED_PROTECTION}} + +{{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf sind zusätzliche Kontroll-/Überwachungsanforderungen an die Softwarenutzung bestimmt und umgesetzt.{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.5 Datenmaskierung und Pseudonymisierung + +*Anforderungsbezug:* ISO/IEC 27001 A.8.11 + +**Anforderung** + + +- **[ISO A.8.11]** Datenmaskierung ist gemäß den Zugriffs- und Datenschutzanforderungen einzusetzen. + +**Umsetzung bei {{ORG_NAME}}** + + +Wo der volle Informationsgehalt für den Verwendungszweck nicht erforderlich ist, werden Daten maskiert, pseudonymisiert oder anonymisiert. Das gilt insbesondere für Test-, Schulungs- und Entwicklungsumgebungen ({{LINK:R11}}), für Auswertungen sowie für Anzeigen mit eingeschränktem Zugriffsbedarf. Umfang und Verfahren richten sich nach der Klassifizierung und den Datenschutzanforderungen ({{LINK:R14}}); die Zulässigkeit einer Wiederherstellung des Personenbezugs und deren Absicherung sind geregelt. + +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_IT_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Asset-Inventar, Zulassung Hard-/Software | +| {{ROLE_ISB}} | Klassifizierungsschema | +| Asset Owner | Pflege einzelner Assets | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_IT_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-08}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R01}}, {{LINK:R08}}, {{LINK:R11}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md b/seed/isms-vorlagenpaket-v2/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md new file mode 100644 index 0000000..f665c97 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R03_Risikomanagement-und-Auditrichtlinie.md @@ -0,0 +1,289 @@ +# Richtlinie Risikomanagement- und Auditrichtlinie + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Identifikation, Bewertung und Behandlung von Informationssicherheitsrisiken sowie interne und unabhängige Überprüfungen. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Risikomanagement + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.4.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 6.1.1, 6.1.2, 8.2, 8.3{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Risikobewertungen werden regelmäßig und anlassbezogen durchgeführt. + +- **[MUSS]** Informationssicherheitsrisiken werden angemessen bewertet (z. B. Eintrittswahrscheinlichkeit und mögliches Schadensausmaß). + +- **[MUSS]** Informationssicherheitsrisiken werden dokumentiert. + +- **[MUSS]** Jedem Informationssicherheitsrisiko ist ein Verantwortlicher (Risk Owner) zugeordnet, der für Bewertung und Behandlung verantwortlich ist. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Verfahren zur Identifikation, Bewertung und Behandlung von Sicherheitsrisiken ist vorhanden. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Kriterien für Bewertung und Behandlung von Sicherheitsrisiken existieren. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Maßnahmen zur Risikobehandlung und ihre Verantwortlichen sind festgelegt und dokumentiert; ein Maßnahmenplan bzw. eine Umsetzungsübersicht wird nachverfolgt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Bei Änderungen des Umfelds (z. B. Organisationsstruktur, Standort, Regularien) erfolgt zeitnah eine Neubewertung. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO 6.1.1]** Bei der Planung des ISMS sind Risiken und Chancen zu bestimmen, die zu behandeln sind. + +- **[ISO 6.1.2]** Ein Prozess zur Risikobeurteilung mit definierten Kriterien, Wiederholbarkeit und vergleichbaren Ergebnissen ist festzulegen und anzuwenden. + +- **[ISO 8.2]** Risikobeurteilungen sind in geplanten Abständen und bei wesentlichen Änderungen durchzuführen und zu dokumentieren. + +- **[ISO 8.3]** Der Risikobehandlungsplan ist umzusetzen; die Ergebnisse sind zu dokumentieren. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Das dokumentierte Risikomanagement-Verfahren (siehe {{LINK:VA-09}}) mit Bewertungs- und Akzeptanzkriterien wird im ISMS-Tool ({{TOOL_NAME}}) umgesetzt: Risiken werden regelmäßig ({{REVIEW_CYCLE}}) und anlassbezogen identifiziert, bewertet (Eintritt × Schaden) und dokumentiert; je Risiko sind Risk Owner, Behandlungsoption und Maßnahmen mit Terminen hinterlegt und werden nachverfolgt. Restrisiken akzeptiert die {{ROLE_MANAGEMENT}} dokumentiert. + +### 3.2 Prüfung der Einhaltung im IS-Betrieb + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.5.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.36{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Einhaltung der Richtlinien wird organisationsweit überprüft. + +- **[MUSS]** Informationssicherheitsrichtlinien und -verfahren werden regelmäßig überprüft. + +- **[MUSS]** Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt. + +- **[MUSS]** Die Einhaltung von Informationssicherheitsanforderungen (z. B. technische Vorgaben) wird regelmäßig überprüft. + +- **[MUSS]** Die Ergebnisse der durchgeführten Überprüfungen werden aufgezeichnet und aufbewahrt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Plan für Inhalt und Rahmenbedingungen (Zeitplan, Umfang, Controls) der durchzuführenden Überprüfungen liegt vor. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.36]** Die Einhaltung der Informationssicherheitspolitik, themenspezifischer Richtlinien, Regeln und Standards ist regelmäßig zu überprüfen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Die Einhaltung von Richtlinien, Verfahren und technischen Anforderungen wird organisationsweit nach dem Audit-Programm ({{LINK:REG-AUDIT-PLAN}}) und dem Audit-/Complianceprüfungs-Verfahren ({{LINK:VA-15}}) durch interne Audits und Kontrollen regelmäßig überprüft (Turnus BL-GOV-01); Ergebnisse werden aufgezeichnet und aufbewahrt, Abweichungen als Maßnahmen im {{TOOL_NAME}} nachverfolgt; Verantwortlich: {{ROLE_ISB}}. + +### 3.3 Unabhängige Überprüfung des ISMS + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.5.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 9.2, A.5.35{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Informationssicherheitsüberprüfungen werden durch eine unabhängige und kompetente Stelle regelmäßig und nach grundlegenden Änderungen durchgeführt. + +- **[MUSS]** Maßnahmen zur Korrektur möglicher Abweichungen werden eingeleitet und verfolgt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Ergebnisse durchgeführter Überprüfungen werden dokumentiert und der Organisationsleitung berichtet. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO 9.2]** Interne Audits sind in geplanten Abständen durchzuführen, um die Konformität und wirksame Umsetzung des ISMS zu prüfen. + +- **[ISO A.5.35]** Der Ansatz der Organisation zur Steuerung der Informationssicherheit ist unabhängig und in geplanten Abständen zu überprüfen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Das ISMS wird regelmäßig und nach grundlegenden Änderungen durch eine unabhängige, kompetente Stelle (interne Revision oder externe Auditierung, z. B. TISAX) überprüft; Ergebnisse werden dokumentiert, der {{ROLE_MANAGEMENT}} berichtet und Abweichungen als Maßnahmen verfolgt. + + +{{#if FLAG_FW_ISO27001}} + +### 3.4 Erklärung zur Anwendbarkeit (SoA) + +*Anforderungsbezug:* ISO/IEC 27001 6.1.3 + +**Anforderung** + + +- **[ISO 6.1.3]** Ein Risikobehandlungsprozess ist festzulegen; erforderliche Controls sind zu bestimmen und mit Annex A abzugleichen (Statement of Applicability). + +**Umsetzung bei {{ORG_NAME}}** + + +Aus der Risikobehandlung wird bestimmt, welche Maßnahmen erforderlich sind; das Ergebnis wird mit Anhang A abgeglichen, um übersehene Maßnahmen zu erkennen. Die Erklärung zur Anwendbarkeit wird im {{TOOL_NAME}} geführt und enthält je Control: Anwendbarkeit, Begründung der Einbeziehung, Herkunft (Risiko-ID, gesetzliche oder vertragliche Anforderung), Umsetzungsstatus, verantwortliche Rolle, Verweis auf Richtlinie und Verfahren sowie Nachweis; bei Ausschluss wird die Begründung dokumentiert. Der Risikobehandlungsplan und die Akzeptanz der verbleibenden Risiken werden von den jeweiligen Risikoeigentümern genehmigt; die SoA wird von {{ROLE_MANAGEMENT}} freigegeben und bei jeder Risikobeurteilung ({{RISK_REVIEW_CYCLE}}) aktualisiert. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.5 Betriebliche Planung und Steuerung + +*Anforderungsbezug:* ISO/IEC 27001 8.1 + +**Anforderung** + + +- **[ISO 8.1]** Die zur Erfüllung der Anforderungen nötigen Prozesse sind zu planen, umzusetzen und zu steuern; geplante Änderungen sind zu kontrollieren. + +**Umsetzung bei {{ORG_NAME}}** + + +Die zur Erfüllung der Informationssicherheitsanforderungen erforderlichen Prozesse sind in den Verfahrensanweisungen festgelegt und werden im {{TOOL_NAME}} gesteuert; je Prozess sind Auslöser, verantwortliche Rolle, Fristen und Nachweise bestimmt. Geplante Änderungen werden gesteuert und ihre Folgen bewertet; unbeabsichtigte Änderungen werden überprüft und erforderlichenfalls korrigiert. Ausgelagerte Prozesse werden über die Lieferantensteuerung ({{LINK:R13}}) bestimmt und überwacht. Nachweise über die planmäßige Durchführung werden im Nachweisregister ({{LINK:NACHWEISREGISTER}}) geführt. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.6 Überwachung, Messung, Analyse und Bewertung + +*Anforderungsbezug:* ISO/IEC 27001 9.1 + +**Anforderung** + + +- **[ISO 9.1]** Die Informationssicherheitsleistung und die Wirksamkeit des ISMS sind zu überwachen, zu messen, zu analysieren und zu bewerten. + +**Umsetzung bei {{ORG_NAME}}** + + +Für die Bewertung der Informationssicherheitsleistung und der Wirksamkeit des ISMS ist festgelegt, was gemessen wird (Kennzahlenblatt im {{TOOL_NAME}}), mit welcher Methode und Datenquelle, in welchem Takt gemessen wird, wer misst, wann die Ergebnisse ausgewertet werden und wer sie auswertet. Die Kennzahlen decken mindestens Vorfallbearbeitung, Schwachstellen- und Patchbehebung, Rezertifizierung von Berechtigungen, Wiederherstellungstests, Awareness-Teilnahme und offene Maßnahmen ab; je Kennzahl sind Zielwert und verantwortliche Rolle hinterlegt. Ergebnisse und Trends gehen {{MGMT_REVIEW_CYCLE}} in die Managementbewertung ein; eine Abweichung vom Zielwert löst eine Maßnahme aus. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.7 Managementbewertung + +*Anforderungsbezug:* ISO/IEC 27001 9.3 + +**Anforderung** + + +- **[ISO 9.3]** Die oberste Leitung hat das ISMS in geplanten Abständen zu bewerten (Managementbewertung). + +**Umsetzung bei {{ORG_NAME}}** + + +{{ROLE_MANAGEMENT}} bewertet das ISMS mindestens {{MGMT_REVIEW_CYCLE}} anhand einer festen Tagesordnung (BL-GOV-02). Eingaben sind mindestens: Status der Maßnahmen aus früheren Bewertungen; Änderungen relevanter interner und externer Themen sowie der Anforderungen interessierter Parteien; Rückmeldungen zur Informationssicherheitsleistung (Nichtkonformitäten und Korrekturmaßnahmen, Überwachungs- und Messergebnisse, Auditergebnisse, Erreichung der Informationssicherheitsziele); Rückmeldungen interessierter Parteien; Ergebnisse der Risikobeurteilung und Status des Risikobehandlungsplans; Verbesserungsmöglichkeiten. Ergebnisse sind Entscheidungen zu Verbesserungsmöglichkeiten und zu Änderungsbedarf am ISMS, jeweils mit verantwortlicher Rolle und Termin. Das Protokoll wird im {{TOOL_NAME}} aufbewahrt. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.8 Nichtkonformität, Korrekturmaßnahmen und fortlaufende Verbesserung + +*Anforderungsbezug:* ISO/IEC 27001 10.1, 10.2 + +**Anforderung** + + +- **[ISO 10.1]** Die Eignung, Angemessenheit und Wirksamkeit des ISMS ist fortlaufend zu verbessern. + +- **[ISO 10.2]** Bei Nichtkonformitäten sind Korrekturen vorzunehmen und Korrekturmaßnahmen zur Beseitigung der Ursachen zu ergreifen. + +**Umsetzung bei {{ORG_NAME}}** + + +Nichtkonformitäten aus Audits, Kontrollen, Vorfällen, Kennzahlenabweichungen und Hinweisen werden im {{TOOL_NAME}} erfasst. Je Fall werden die Sofortkorrektur und der Umgang mit den Folgen festgelegt, die Ursache analysiert und bewertet, ob gleichartige Nichtkonformitäten anderswo bestehen oder auftreten können. Erforderliche Korrekturmaßnahmen werden mit verantwortlicher Rolle und Termin umgesetzt; ihre Wirksamkeit wird nach Ablauf des festgelegten Wirksamkeitsintervalls bewertet und erforderlichenfalls werden Risiken, Maßnahmen und Dokumente angepasst. Art der Nichtkonformität, ergriffene Maßnahmen und Ergebnis der Wirksamkeitsbewertung werden aufbewahrt. Eignung, Angemessenheit und Wirksamkeit des ISMS werden fortlaufend verbessert; der Nachweis erfolgt über Kennzahlen und Managementbewertung. + +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Risikomanagement, Audits | +| {{ROLE_MANAGEMENT}} | Risikoakzeptanz | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-09}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R01}}, {{LINK:R04}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md b/seed/isms-vorlagenpaket-v2/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md new file mode 100644 index 0000000..5bb14b5 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R04_Incident-Notfall-und-Kontinuitaetsrichtlinie.md @@ -0,0 +1,383 @@ +# Richtlinie Incident-, Notfall- und Kontinuitätsrichtlinie + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Meldung und Behandlung von Sicherheitsereignissen, Krisenmanagement sowie Notfall- und Kontinuitätsplanung. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Meldung von Sicherheitsereignissen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.6.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.24, A.6.8{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Eine Definition für ein meldepflichtiges Sicherheitsereignis oder eine Beobachtung existiert und ist Beschäftigten und relevanten Stakeholdern bekannt. + +- **[MUSS]** Angemessene, risikoorientierte Mechanismen zur Meldung von Sicherheitsereignissen sind definiert, umgesetzt und allen relevanten Meldenden bekannt. + +- **[MUSS]** Angemessene Kanäle zur Kommunikation mit Meldenden existieren. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine gemeinsame Anlaufstelle für die Ereignismeldung existiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Verschiedene Meldekanäle je nach wahrgenommener Schwere (Echtzeit für gravierende Ereignisse/Notfälle sowie asynchrone Mechanismen wie Tickets oder E-Mail) sind verfügbar. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Beschäftigte sind verpflichtet und geschult, relevante Ereignisse zu melden. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Sicherheitsereignisse können auch durch Externe gemeldet werden; die einschlägigen Aspekte werden berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Der Mechanismus und die Information, wie Vorfälle gemeldet werden, sind für alle relevanten Meldenden zugänglich. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Rückmeldeverfahren an die Meldenden ist etabliert. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Tests und Übungen der Ereignis- und Beobachtungsmeldung werden regelmäßig durchgeführt. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.24]** Das Management von Informationssicherheitsvorfällen ist zu planen und vorzubereiten (Rollen, Prozesse, Verantwortlichkeiten). + +- **[ISO A.6.8]** Ein Mechanismus zur zeitnahen Meldung beobachteter oder vermuteter Informationssicherheitsereignisse ist bereitzustellen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Eine bekannte Definition meldepflichtiger Ereignisse und ein niedrigschwelliger Meldeweg (Meldebutton/Formular im {{TOOL_TICKET}} bzw. ISMS-Tool, E-Mail an {{ROLE_ISB}}, für gravierende Fälle Echtzeitkanal) stehen allen Beschäftigten und Externen zur Verfügung; der Meldeweg ist über Onboarding/Awareness (BL-HR-01) bekannt, ein Rückmeldeverfahren ist etabliert (siehe {{LINK:VA-01}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +{{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf werden Tests und Übungen der Ereignismeldung regelmäßig durchgeführt.{{/if}} +{{/if}} + +### 3.2 Behandlung von Sicherheitsereignissen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.6.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.25, A.5.26, A.5.27, A.5.28{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Gemeldete Ereignisse werden ohne unangemessene Verzögerung bearbeitet. + +- **[MUSS]** Eine angemessene Reaktion auf gemeldete Sicherheitsereignisse ist sichergestellt. + +- **[MUSS]** Lessons Learned fließen in die kontinuierliche Verbesserung ein. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Gemeldete Ereignisse werden bei der Bearbeitung kategorisiert (z. B. Personal, physisch, Cyber), qualifiziert (z. B. nicht sicherheitsrelevant, Beobachtung, Verbesserungsvorschlag, Schwachstelle, Vorfall) und priorisiert (z. B. gering, mittel, schwer, kritisch). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Verantwortlichkeiten für die Behandlung von Ereignissen je Kategorie sind definiert und zugewiesen. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine Strategie zur Meldung potenziell strafrechtlich relevanter Aspekte an zuständige Behörden, sofern erforderlich, existiert. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Maximale Reaktionszeiten je Klasse, Kategorie und Schwere sind definiert. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Nicht prioritätsgerecht bearbeitete Ereignisse werden eskaliert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Gesetzliche, regulatorische und vertragliche Meldepflichten sowie zugehörige Kontaktinformationen sind bekannt. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Eine Kommunikationsstrategie für sicherheitsrelevante Ereignisse existiert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Verfahren zur Reaktion auf Sicherheitsvorfälle bei Lieferanten sind etabliert; die einschlägigen Aspekte werden berücksichtigt. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Die Behandlung von Ereignissen unterschiedlicher Kategorien und Prioritäten wird regelmäßig getestet; die einschlägigen Aspekte werden berücksichtigt. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.25]** Informationssicherheitsereignisse sind zu bewerten und es ist zu entscheiden, ob sie als Informationssicherheitsvorfälle einzustufen sind. + +- **[ISO A.5.26]** Auf Informationssicherheitsvorfälle ist gemäß dokumentierten Verfahren zu reagieren. + +- **[ISO A.5.27]** Aus Informationssicherheitsvorfällen gewonnene Erkenntnisse sind zur Stärkung der Maßnahmen zu nutzen. + +- **[ISO A.5.28]** Verfahren zur Identifizierung, Sammlung, Beschaffung und Aufbewahrung von Beweismaterial zu Vorfällen sind festzulegen und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Ereignisse werden ohne Verzögerung nach einem definierten Incident-Verfahren (siehe {{LINK:VA-01}}) im {{TOOL_TICKET}} kategorisiert, qualifiziert, priorisiert, behandelt und dokumentiert; Verantwortlichkeiten und Eskalationswege sind zugewiesen ({{ROLE_ISB}} koordiniert, {{ROLE_IT_LEAD}} setzt um). Lessons Learned fließen in die Verbesserung ein; eine Strategie zur Behörden-/Strafverfolgungsmeldung besteht. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind maximale Reaktionszeiten je Schwere definiert, Eskalationen für nicht prioritätsgerecht bearbeitete Ereignisse geregelt, Meldepflichten und Kontakte bekannt, eine Kommunikationsstrategie sowie ein Verfahren für Lieferantenvorfälle etabliert. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf wird die Ereignisbehandlung regelmäßig getestet.{{/if}} +{{/if}} + +### 3.3 Krisenmanagement + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 1.6.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.29{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Ein angemessener Plan zur Reaktion auf und Bewältigung von Krisensituationen existiert und die erforderlichen Ressourcen sind verfügbar. + +- **[MUSS]** Verantwortlichkeiten und Befugnisse für das Krisenmanagement sind definiert, dokumentiert und zugewiesen. + +- **[MUSS]** Die verantwortlichen Beschäftigten sind definiert und für ihre Aufgabe qualifiziert. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Methoden zur Erkennung von Krisensituationen sind etabliert; allgemeine Anzeichen und spezifische vorhersehbare Krisen sind identifiziert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Verfahren zur Auslösung und/oder Eskalation des Krisenmanagements ist vorhanden. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Strategische Ziele und ihre Priorität in Krisensituationen sind definiert und relevantem Personal bekannt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Krisenstab ist definiert und genehmigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Krisenrichtlinien und -verfahren sind definiert und genehmigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Krisenplanung wird regelmäßig überprüft und aktualisiert. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Relevante unterschiedliche potenzielle Krisenszenarien sind identifiziert. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Notwendige Ressourcen und Informationen zur Krisenbewältigung (z. B. Kommunikationsinfrastruktur, Verfügbarkeit von Kontakt- und Risikoinformationen) sind identifiziert; angemessene Maßnahmen zur Sicherstellung der Verfügbarkeit bzw. Ausfallplanung sind vorhanden. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Eine Kommunikationsstrategie für Krisensituationen existiert. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Effizienz, Durchführbarkeit und Angemessenheit der Krisenplanung werden regelmäßig bewertet. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Stichprobenbasierte Tests der Krisenplanung werden durchgeführt (z. B. Simulation, Tabletop-Übungen mit Schlüsselpersonal). (A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Krisenübungen und Simulationen unter Einbindung aller relevanten Personen, einschließlich Entscheidungsträger, werden regelmäßig durchgeführt. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.29]** Die Aufrechterhaltung der Informationssicherheit während Störungen ist zu planen und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Ein Krisenmanagement mit Plan, definiertem und genehmigtem Krisenstab, Rollen, Auslöse-/Eskalations-, Kommunikations- und Entscheidungswegen sowie strategischen Zielen ist etabliert (Auslösung/Wiederanlauf siehe {{LINK:VA-02}}); erforderliche Ressourcen sind verfügbar, Verantwortliche qualifiziert. Erkennungsmethoden bestehen, die Krisenplanung wird regelmäßig überprüft und aktualisiert; der Krisenstab wird durch die {{ROLE_MANAGEMENT}} einberufen. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind relevante Krisenszenarien identifiziert, notwendige Ressourcen/Informationen und eine Kommunikationsstrategie sichergestellt, die Planung wird regelmäßig bewertet und stichprobenartig getestet (Tabletop). {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf werden regelmäßig Krisenübungen mit allen relevanten Personen inkl. Entscheidungsträgern durchgeführt.{{/if}} +{{/if}} + +### 3.4 Kontinuitätsplanung für IT-Dienste + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.8{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.30, A.8.14{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Kritische IT-Dienste sind identifiziert und die Geschäftsauswirkung wird berücksichtigt. + +- **[MUSS]** Anforderungen und Verantwortlichkeiten für Kontinuität und Wiederherstellung dieser IT-Dienste sind relevanten Stakeholdern bekannt und erfüllt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Kritische IT-Systeme sind identifiziert; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine Kontinuitätsplanung existiert und wird regelmäßig überprüft und aktualisiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Kontinuitätsplanung umfasst mindestens (D)DoS-Angriffe, erfolgreiche Ransomware-Angriffe und andere Sabotage, Systemausfallszenarien sowie Naturkatastrophen, die kritische IT-Systeme betreffen. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Kontinuitätsplanung enthält vordefinierte Zeitrahmen (Recovery Time Objective) für die Wiederaufnahme des Betriebs. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Angemessene SLAs mit externen Dienstleistern entsprechend der Kontinuitätsplanung bestehen. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Kontinuitätspläne umfassen die Koordination vertraglich vereinbarter Kommunikation mit Geschäftspartnern. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Kontinuitätsplanung wird regelmäßig getestet, inkl. vollständiger Wiederherstellung in einen bekannten Zustand und Einhaltung definierter Zielzeiten. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Eine Backup- und Wiederherstellungsstrategie für kritische IT-Dienste und Informationen ist definiert und umgesetzt. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugte Veränderung/Löschung durch Schadsoftware geschützt. (I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Backups kritischer IT-Dienste und Informationen sind ausreichend gegen unbefugten Zugriff durch Schadsoftware oder Betreiber geschützt. (C, I) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Die Kontinuitätsplanung ist mit den Kontinuitätsplänen relevanter externer Dienstleister abgestimmt. (A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Die Fortführung wesentlicher Kern- und Geschäftsfunktionen mit minimalem oder keinem Verlust an Betriebskontinuität ist möglich; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Die Kontinuitätsplanung wird regelmäßig getestet. Testszenarien, Ergebnisse und Lessons Learned werden aufgezeichnet. (I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.30]** Die IKT-Bereitschaft ist auf Basis der Business-Continuity-Ziele und -Anforderungen zu planen, umzusetzen und zu testen. + +- **[ISO A.8.14]** Informationsverarbeitende Einrichtungen sind mit ausreichender Redundanz auszulegen, um die Verfügbarkeitsanforderungen zu erfüllen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Kritische IT-Dienste sind mit Geschäftsauswirkung im Register kritischer IT-Dienste ({{LINK:REG-CRIT-SERVICES}}) (inkl. BIA-Einstufung, RTO/RPO, Wiederanlaufreihenfolge) erfasst; Anforderungen und Verantwortlichkeiten für Kontinuität/Wiederherstellung sind bekannt und erfüllt. Eine Kontinuitätsplanung (inkl. (D)DoS, Ransomware, Ausfall, Naturkatastrophen) besteht, wird regelmäßig überprüft und über das IT-Notfallverfahren umgesetzt (siehe {{LINK:VA-02}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind RTO/RPO, SLAs mit Dienstleistern, Partnerkommunikation, regelmäßige Volltests sowie eine geschützte Backup-/Recovery-Strategie (immutable/isoliert) etabliert. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf ist die Planung mit externen Dienstleistern abgestimmt, die Fortführung wesentlicher Funktionen sichergestellt und Tests inkl. Lessons Learned werden aufgezeichnet.{{/if}} +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Vorfallskoordination | +| {{ROLE_IT_LEAD}} | Notfall-/Wiederanlaufplanung | +| {{ROLE_MANAGEMENT}} | Krisenstab | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-01}}, {{LINK:VA-02}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R03}}, {{LINK:R10}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R05_Personalsicherheit-und-Awareness.md b/seed/isms-vorlagenpaket-v2/richtlinien/R05_Personalsicherheit-und-Awareness.md new file mode 100644 index 0000000..d730f49 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R05_Personalsicherheit-und-Awareness.md @@ -0,0 +1,221 @@ +# Richtlinie Personalsicherheit und Awareness + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_HR_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Eignung, vertragliche Verpflichtung sowie Schulung und Sensibilisierung des Personals. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Qualifikation für sensible Tätigkeiten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 7.2, A.6.1{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Sensible Arbeitsbereiche und Tätigkeiten sind bestimmt. + +- **[MUSS]** Die Anforderungen an Beschäftigte hinsichtlich ihrer Stellenprofile sind bestimmt und erfüllt. + +- **[MUSS]** Die Identität potenzieller Beschäftigter wird verifiziert (z. B. Prüfung von Ausweisdokumenten). +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die persönliche Eignung potenzieller Beschäftigter wird mit einfachen Methoden überprüft (z. B. Vorstellungsgespräch). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine erweiterte Eignungsprüfung abhängig vom Arbeitsbereich und der Tätigkeit wird durchgeführt (z. B. Assessment-Center, Prüfung von Referenzen, Zeugnissen und Führungszeugnissen). +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO 7.2]** Erforderliche Kompetenzen sind zu bestimmen und sicherzustellen; entsprechende Nachweise sind zu führen. + +- **[ISO A.6.1]** Hintergrundüberprüfungen von Bewerbern sind angemessen zu den Geschäftsanforderungen und gesetzeskonform durchzuführen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Sensible Arbeitsbereiche und Tätigkeiten sind im Register sensibler Tätigkeiten ({{LINK:REG-SENS-ROLES}}) bestimmt und mit der geforderten Prüftiefe hinterlegt; Anforderungen an Positionen sind in Stellenbeschreibungen dokumentiert und werden erfüllt. Identitätsverifizierung sowie die persönliche und – bei sensiblen Rollen – erweiterte Eignungsprüfung (Gespräch, Referenzen, Führungszeugnis im rechtlich zulässigen Rahmen) erfolgen nach dem Eignungs- und Verifizierungsverfahren ({{LINK:VA-14}}); Verantwortlich: {{ROLE_HR_LEAD}}; Nachweis in der Personalakte. + +### 3.2 Vertragliche Verpflichtung des Personals + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.6.2, A.6.5, A.6.6{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Eine Vertraulichkeitsverpflichtung ist in Kraft. + +- **[MUSS]** Eine Verpflichtung zur Einhaltung der Informationssicherheitsrichtlinien ist in Kraft. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine über den Arbeitsvertrag hinausgehende Vertraulichkeitsverpflichtung ist in Kraft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Informationssicherheitsaspekte werden in den Arbeitsverträgen der Beschäftigten berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Verfahren zum Umgang mit Verstößen gegen diese Verpflichtungen ist beschrieben. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.6.2]** Die arbeitsvertraglichen Vereinbarungen legen die Verantwortlichkeiten für die Informationssicherheit fest. + +- **[ISO A.6.5]** Fortbestehende Informationssicherheitsverantwortlichkeiten nach Beendigung oder Wechsel des Beschäftigungsverhältnisses sind zu definieren und durchzusetzen. + +- **[ISO A.6.6]** Vertraulichkeits- bzw. Geheimhaltungsvereinbarungen sind zu identifizieren, zu dokumentieren und regelmäßig zu überprüfen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Alle Beschäftigten werden bei Eintritt vertraglich zur Vertraulichkeit und zur Einhaltung der Informationssicherheitsrichtlinien verpflichtet ({{ROLE_HR_LEAD}}); Informationssicherheitsaspekte sind Bestandteil der Arbeitsverträge, die Vertraulichkeit gilt nachvertraglich fort. Ein dokumentiertes Verfahren zum Umgang mit Verstößen (siehe {{LINK:VA-14}}) ist etabliert; der Nachweis wird in der Personalakte geführt. + +### 3.3 Sensibilisierung und Schulung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 7.3, A.6.3{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Beschäftigte werden geschult und sensibilisiert. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Konzept für Sensibilisierung und Schulung der Beschäftigten ist erstellt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Zielgruppen für Schulungs- und Sensibilisierungsmaßnahmen (z. B. Führungskräfte, Administratoren, Beschäftigte mit Zugang zu Kundennetzen, Fertigungspersonal) sind identifiziert und im Konzept berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Das Konzept ist durch die verantwortliche Leitung genehmigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Schulungs- und Sensibilisierungsmaßnahmen werden regelmäßig und anlassbezogen durchgeführt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Teilnahme an Schulungs- und Sensibilisierungsmaßnahmen wird dokumentiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ansprechpartner für Informationssicherheit sind den Beschäftigten bekannt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO 7.3]** Personen unter Aufsicht der Organisation müssen sich der Politik, ihres Beitrags und der Folgen von Verstößen bewusst sein. + +- **[ISO A.6.3]** Beschäftigte erhalten angemessene Awareness, Aus- und Weiterbildung sowie regelmäßige Aktualisierungen der relevanten Richtlinien. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Ein von der Leitung genehmigtes, rollenspezifisches Schulungs-/Awareness-Konzept (BL-HR-01) ist etabliert; Beschäftigte werden bei Eintritt und danach mindestens {{REVIEW_CYCLE}} sowie anlassbezogen geschult (Ablauf siehe {{LINK:VA-12}}). Zielgruppen sind identifiziert, Teilnahmenachweise werden im {{TOOL_NAME}} geführt, Ansprechpartner für Informationssicherheit sind bekannt; die Wirksamkeit wird (z. B. Phishing-Simulation) geprüft. + + +{{#if FLAG_FW_ISO27001}} + +### 3.4 Vorgehen bei Verstößen + +*Anforderungsbezug:* ISO/IEC 27001 A.6.4 + +**Anforderung** + + +- **[ISO A.6.4]** Ein Disziplinarverfahren für Verstöße gegen die Informationssicherheit ist festzulegen und zu kommunizieren. + +**Umsetzung bei {{ORG_NAME}}** + + +Für Verstöße gegen die Informationssicherheitsvorgaben besteht ein abgestuftes, dokumentiertes Vorgehen, das im Voraus kommuniziert ist. Es berücksichtigt Art und Schwere des Verstoßes, Vorsatz oder Fahrlässigkeit, Wiederholung sowie den Schulungsstand der betroffenen Person. Das Verfahren wird von {{ROLE_HR_LEAD}} in Abstimmung mit {{ROLE_ISB}} geführt; arbeitsrechtliche Vorgaben und Mitbestimmungsrechte werden gewahrt. Die Anwendung wird vertraulich dokumentiert. + +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_HR_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_HR_LEAD}} | Verpflichtung, Eignung | +| {{ROLE_ISB}} | Awareness/Schulung | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_HR_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-12}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R01}}, {{LINK:R06}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md b/seed/isms-vorlagenpaket-v2/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md new file mode 100644 index 0000000..7fc1871 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R06_Mobiles-Arbeiten-und-mobile-Geraete.md @@ -0,0 +1,151 @@ +# Richtlinie Mobiles Arbeiten und mobile Geräte + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt mobiles Arbeiten sowie den Umgang mit mobilen IT-Geräten und Datenträgern. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +{{#if FLAG_MOBILE_WORK}} +### 3.1 Mobiles Arbeiten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 2.1.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.6.7{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Anforderungen an mobiles Arbeiten sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die einschlägigen Aspekte des mobilen Arbeitens werden berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Sensibilisierung der Beschäftigten. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Schutzmaßnahmen gegen Abhören und Einsehen sind umgesetzt. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.6.7]** Sicherheitsmaßnahmen für das Arbeiten außerhalb der Räumlichkeiten der Organisation sind umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Mobiles Arbeiten ist in dieser Richtlinie und der zugehörigen Regelung mobiles Arbeiten (hinterlegt im {{TOOL_NAME}}) festgelegt und die Anforderungen sind erfüllt; der Zugriff erfolgt ausschließlich über {{TECH_VPN}} mit MFA (BL-IAM-02) und freigegebene, verschlüsselte Geräte (BL-CRY-03). Die Beschäftigten sind sensibilisiert (BL-HR-01). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind Schutzmaßnahmen gegen Abhören und Einsehen umgesetzt (z. B. Sichtschutz, ruhige Umgebung, Clean-Screen). +{{/if}} + +{{/if}} +{{#if FLAG_MOBILE_DEVICES}} +### 3.2 Mobile IT-Geräte und Datenträger + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 3.1.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.7.9, A.7.10, A.8.1{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Anforderungen an mobile IT-Geräte und mobile Datenträger sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Registrierung der IT-Geräte. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Generelle Verschlüsselung mobiler Datenträger bzw. der darauf gespeicherten Informationswerte. Wo technisch nicht machbar, werden Informationen durch gleichwertige Maßnahmen geschützt. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.7.9]** Assets, die außerhalb der Räumlichkeiten genutzt werden, sind zu schützen. + +- **[ISO A.7.10]** Speichermedien sind über ihren gesamten Lebenszyklus (Erwerb, Nutzung, Transport, Entsorgung) entsprechend dem Klassifizierungsschema zu schützen. + +- **[ISO A.8.1]** Informationen, die auf Endgeräten der Benutzer gespeichert, verarbeitet oder darüber zugänglich sind, sind zu schützen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Die Anforderungen an mobile Geräte und Datenträger sind bestimmt und erfüllt: Geräte sind über {{TECH_MDM}} registriert und zentral verwaltet, nur freigegebene Geräte werden genutzt; Verlustmeldung erfolgt über den Meldeweg (R04) und das {{TOOL_TICKET}}, Sperre/Löschung bei Verlust über {{TECH_MDM}} (BL-EP-02). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind mobile Datenträger bzw. die darauf gespeicherten Informationen generell verschlüsselt (BL-CRY-03); wo nicht machbar, greifen gleichwertige Schutzmaßnahmen. +{{/if}} + +{{/if}} +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Sicherheitsanforderungen | +| {{ROLE_IT_LEAD}} | Technische Umsetzung | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R05}}, {{LINK:R07}}, {{LINK:R08}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R07_Physische-Sicherheit.md b/seed/isms-vorlagenpaket-v2/richtlinien/R07_Physische-Sicherheit.md new file mode 100644 index 0000000..2c061f7 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R07_Physische-Sicherheit.md @@ -0,0 +1,173 @@ +# Richtlinie Physische Sicherheit + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt physischen Schutz durch Sicherheitszonen, Zutrittsschutz und den Umgang mit unterstützenden Betriebsmitteln. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Sicherheitszonen und Zutritt + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 3.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.7.1, A.7.2, A.7.3, A.7.4, A.7.6{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Ein Sicherheitszonenkonzept einschließlich zugehöriger Schutzmaßnahmen auf Basis der Anforderungen an die Handhabung von Informationswerten ist vorhanden. + +- **[MUSS]** Die definierten Schutzmaßnahmen sind umgesetzt. + +- **[MUSS]** Der Verhaltenskodex für Sicherheitszonen ist allen beteiligten Personen bekannt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Verfahren für die Vergabe und den Entzug von Zutrittsrechten sind etabliert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Richtlinien für das Besuchermanagement (einschließlich Registrierung und Begleitung von Besuchern) sind definiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Richtlinien für das Mitführen und Nutzen mobiler IT-Geräte und Datenträger (z. B. Registrierung, Kennzeichnungspflichten) sind definiert und umgesetzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Netzwerk-/Infrastrukturkomponenten (eigene oder Kundennetze) sind gegen unbefugten Zugriff geschützt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Externe Liegenschaften zur Speicherung/Verarbeitung von Informationswerten sind im Zonenkonzept berücksichtigt (z. B. Lagerräume, Werkstätten, Teststrecken, Rechenzentren). +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Schutzmaßnahmen gegen einfaches Abhören und Einsehen sind umgesetzt. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.7.1]** Sicherheitsperimeter sind zu definieren und zum Schutz von Bereichen mit Informationen und Assets zu nutzen. + +- **[ISO A.7.2]** Sichere Zutrittskontrollen und Zutrittspunkte sind einzurichten, um den Zugang auf Berechtigte zu beschränken. + +- **[ISO A.7.3]** Physische Sicherheit für Büros, Räume und Einrichtungen ist zu gestalten und umzusetzen. + +- **[ISO A.7.4]** Räumlichkeiten sind kontinuierlich auf unbefugten physischen Zugang zu überwachen. + +- **[ISO A.7.6]** Für das Arbeiten in Sicherheitsbereichen sind Maßnahmen festzulegen und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Ein Sicherheitszonenkonzept (BL-PHY-01) mit umgesetzten Schutzmaßnahmen und bekanntem Verhaltenskodex ist vorhanden; Zutrittsrechte werden über das {{TOOL_TICKET}} bedarfsorientiert vergeben, dokumentiert und bei Wegfall entzogen (BL-PHY-02, Ablauf siehe {{LINK:VA-17}}). Besuchermanagement, Regeln für mobile Geräte, Schutz von Netz-/Infrastrukturkomponenten und externe Liegenschaften sind berücksichtigt. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind zusätzliche Schutzmaßnahmen gegen einfaches Abhören und Einsehen umgesetzt. +{{/if}} + + + + +{{#if FLAG_FW_ISO27001}} + +### 3.2 Umgebungsschutz, Versorgung, Verkabelung und Wartung + +*Anforderungsbezug:* ISO/IEC 27001 A.7.5, A.7.8, A.7.11, A.7.12, A.7.13 + +**Anforderung** + + +- **[ISO A.7.5]** Schutz gegen physische und umweltbedingte Bedrohungen ist zu gestalten und umzusetzen. + +- **[ISO A.7.8]** Betriebsmittel sind sicher zu platzieren und zu schützen. + +- **[ISO A.7.11]** Einrichtungen sind vor Ausfällen und Störungen der Versorgung (z. B. Strom, Klima) zu schützen. + +- **[ISO A.7.12]** Verkabelung für Strom und Daten ist vor Abhören, Störung und Beschädigung zu schützen. + +- **[ISO A.7.13]** Betriebsmittel sind ordnungsgemäß zu warten, um Verfügbarkeit und Integrität sicherzustellen. + +**Umsetzung bei {{ORG_NAME}}** + + +Standorte und technische Einrichtungen sind gegen physische und umweltbedingte Bedrohungen geschützt (BL-PHY-03): Brandfrüherkennung, Schutz gegen Wasser und Feuchtigkeit, Temperatur- und Feuchteüberwachung in Technikräumen sowie Berücksichtigung standortspezifischer Gefahren. Betriebsmittel sind so platziert, dass Einsicht, unbefugter Zugriff und Umgebungsrisiken minimiert werden. Strom- und Klimaversorgung sind für kritische Systeme unterbrechungsfrei ausgelegt und werden regelmäßig geprüft. Strom- und Datenverkabelung ist gegen Beschädigung und unbefugten Zugriff geschützt und dokumentiert. Betriebsmittel werden nach Herstellervorgabe gewartet; Wartungen erfolgen nur durch berechtigtes Personal, werden geplant und protokolliert und bei externer Durchführung begleitet. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.3 Aufgeräumter Arbeitsplatz und Bildschirmsperre + +*Anforderungsbezug:* ISO/IEC 27001 A.7.7 + +**Anforderung** + + +- **[ISO A.7.7]** Regeln für einen aufgeräumten Arbeitsplatz und gesperrte Bildschirme sind festzulegen und umzusetzen. + +**Umsetzung bei {{ORG_NAME}}** + + +Es gelten verbindliche Regeln für einen aufgeräumten Arbeitsplatz und gesperrte Bildschirme (BL-PHY-04): Schutzbedürftige Unterlagen und Datenträger werden bei Abwesenheit verschlossen aufbewahrt; Bildschirme werden beim Verlassen des Arbeitsplatzes gesperrt und sperren automatisch nach {{SESSION_TIMEOUT}}. Ausdrucke werden unmittelbar entnommen, nicht mehr benötigte Unterlagen schutzbedarfsgerecht vernichtet (BL-DEL-01). Die Regeln gelten auch im Homeoffice und an mobilen Arbeitsplätzen ({{LINK:R06}}); die Einhaltung wird stichprobenartig geprüft. + +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_IT_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Zonen, Zutritt, Betriebsmittel | +| {{ROLE_ISB}} | Vorgaben | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_IT_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R02}}, {{LINK:R06}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md b/seed/isms-vorlagenpaket-v2/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md new file mode 100644 index 0000000..0c62f0a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R08_Identitaets-und-Zugriffsmanagement.md @@ -0,0 +1,314 @@ +# Richtlinie Identitäts- und Zugriffsmanagement + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Identifikationsmittel, sichere Anmeldung, Kontenverwaltung sowie Vergabe und Kontrolle von Zugriffsrechten. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Umgang mit Identifikationsmitteln + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.16{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Anforderungen an den Umgang mit Identifikationsmitteln über den gesamten Lebenszyklus sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Identifikationsmittel können nur unter kontrollierten Bedingungen erstellt werden. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Eine Strategie zur Sperrung oder Ungültigmachung von Identifikationsmitteln im Verlustfall ist vorbereitet und soweit möglich umgesetzt. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.16]** Der vollständige Lebenszyklus von Identitäten ist zu verwalten. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Identifikationsmittel (Benutzerkennungen, Token, Zertifikate) werden über den Lebenszyklus eindeutig personenbezogen und unter kontrollierten Bedingungen über das zentrale Verzeichnis ({{TOOL_IAM}}) vergeben; Ausgabe, Rücknahme und Sperrung werden im {{TOOL_TICKET}} beantragt, genehmigt und dokumentiert (BL-IAM-07, siehe {{LINK:VA-03}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf besteht eine umgesetzte Strategie zur Sperrung/Ungültigmachung von Identifikationsmitteln im Verlustfall. +{{/if}} + +### 3.2 Sichere Anmeldung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.5{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Verfahren zur Benutzerauthentifizierung sind auf Basis einer Risikobewertung ausgewählt; mögliche Angriffsszenarien (z. B. direkte Erreichbarkeit über das Internet) wurden berücksichtigt. + +- **[MUSS]** Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Authentifizierungsverfahren sind auf Basis der geschäftlichen und sicherheitsrelevanten Anforderungen definiert und umgesetzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Benutzer werden mindestens durch starke Passwörter nach bewährten und anerkannten Praktiken authentifiziert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt (z. B. Privileged Access Management, Zwei-Faktor-Authentifizierung). +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Abhängig von der Risikobewertung sind Authentifizierung und Zugangskontrolle durch ergänzende Maßnahmen verstärkt (z. B. kontinuierliche Zugriffsüberwachung, starke Authentifizierung, automatische Abmeldung, Sperre bei Inaktivität, Brute-Force-Prävention). (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Vor dem Zugriff auf Daten mit sehr hohem Schutzbedarf werden Benutzer mittels starker Authentifizierung (z. B. Zwei-Faktor) nach dem Stand der Technik authentifiziert. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.5]** Sichere Authentisierungstechnologien und -verfahren sind auf Basis der Zugriffsbeschränkungen und der Zugriffssteuerungsrichtlinie einzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Die Authentifizierungsverfahren sind risikobasiert ausgewählt und entsprechen dem Stand der Technik; Passwortvorgaben nach BL-IAM-01 (mind. {{PW_MIN_LENGTH}} Zeichen, {{PW_COMPLEXITY}}, {{PW_ROTATION}}) werden über das zentrale Verzeichnis ({{TOOL_IAM}}) erzwungen. Für Fernzugriffe, administrative Zugänge und Cloud-Dienste wird MFA (BL-IAM-02) über {{TECH_MFA}} durchgesetzt; privilegierte Konten nutzen höherwertige Verfahren (PAM). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind Authentifizierung/Zugangskontrolle durch ergänzende Maßnahmen verstärkt (Zugriffsüberwachung, Auto-Logout BL-IAM-03, Sperre BL-IAM-04, Brute-Force-Schutz). {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf erfolgt der Zugriff nur nach starker Authentifizierung (Zwei-Faktor).{{/if}} +{{/if}} + +### 3.3 Benutzerkonten und Anmeldeinformationen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 4.1.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.17{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Das Erstellen, Ändern und Löschen von Benutzerkonten wird durchgeführt. + +- **[MUSS]** Eindeutige und personalisierte Benutzerkonten werden verwendet. + +- **[MUSS]** Die Nutzung von Sammelkonten ist geregelt (z. B. beschränkt auf Fälle, in denen Nachvollziehbarkeit verzichtbar ist). + +- **[MUSS]** Benutzerkonten werden unmittelbar nach dem Ausscheiden des Nutzers deaktiviert (z. B. bei Vertragsende). + +- **[MUSS]** Benutzerkonten werden regelmäßig überprüft. + +- **[MUSS]** Die Anmeldeinformationen werden dem Nutzer auf sichere Weise bereitgestellt. + +- **[MUSS]** Eine Richtlinie zum Umgang mit Anmeldeinformationen ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Basiskonto mit minimalen Zugriffsrechten und Funktionalitäten existiert und wird genutzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Vom Hersteller vorkonfigurierte Standardkonten und -passwörter sind deaktiviert (z. B. Sperren oder Passwortänderung). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Benutzerkonten werden durch die verantwortliche Stelle erstellt oder autorisiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Das Erstellen von Benutzerkonten unterliegt einem Genehmigungsprozess (Vier-Augen-Prinzip). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Benutzerkonten von Dienstleistern werden nach Abschluss ihrer Aufgabe deaktiviert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Fristen für das Deaktivieren und Löschen von Benutzerkonten sind definiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Verwendung von Standardpasswörtern wird technisch verhindert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Bei starker Authentifizierung ist die Nutzung des Mediums (z. B. Besitzfaktor) sicher. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Benutzerkonten werden regelmäßig überprüft; dies umfasst auch Konten in IT-Systemen von Kunden. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Interaktive Anmeldung für Dienstkonten (technische Konten) wird technisch verhindert. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.17]** Die Zuteilung und Verwaltung von Authentisierungsinformationen ist durch einen geeigneten Verwaltungsprozess zu steuern. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Benutzerkonten werden über einen definierten Lebenszyklus (Joiner/Mover/Leaver) (siehe {{LINK:VA-03}}) eindeutig personalisiert im zentralen Verzeichnis ({{TOOL_IAM}}) verwaltet; Auslöser sind {{TOOL_TICKET}}-Aufträge aus HR-/Vorgesetztenmeldungen. Konten Ausgeschiedener werden unverzüglich deaktiviert, Konten regelmäßig überprüft (auch in Kundensystemen), Sammelkonten sind geregelt. Anmeldeinformationen werden sicher bereitgestellt; Standardkonten/-passwörter sind deaktiviert, Basiskonten mit Minimalrechten genutzt, Erstellung erfolgt im Vier-Augen-Prinzip, interaktive Anmeldung technischer Konten ist unterbunden. + +### 3.4 Zugriffsrechte + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 4.2.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.15, A.5.18, A.8.2, A.8.3, A.8.18{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Anforderungen an die Verwaltung von Zugriffsrechten (Autorisierung) sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. + +- **[MUSS]** Die für normale und privilegierte Benutzerkonten sowie technische Konten vergebenen Zugriffsrechte werden regelmäßig überprüft, auch in IT-Systemen von Kunden. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Strategien zur Autorisierung von Zugriffen auf Informationen sind vorbereitet. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Autorisierungsrollen werden verwendet. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Rechte werden nach dem Need-to-use-Prinzip und gemäß Rolle und/oder Verantwortungsbereich vergeben. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Normale Benutzerkonten erhalten keine privilegierten Zugriffsrechte. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Zugriffsrechte des Nutzers werden nach Änderung seiner Verantwortlichkeiten aktualisiert. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Zugriffsrechte werden durch den verantwortlichen internen Information Officer genehmigt. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Informationen werden auf Inhaltsebene (z. B. Dateiebene) verschlüsselt gespeichert, um unbefugten Zugriff (auch privilegierter Nutzer) zu verhindern. Wo Verschlüsselung nicht machbar ist, greifen gleichwertige Maßnahmen. (C) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Bestehende Zugriffsrechte werden in kürzeren Abständen (z. B. quartalsweise) überprüft. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.15]** Regeln zur Steuerung des physischen und logischen Zugriffs auf Informationen und Assets sind auf Basis der Geschäfts- und Informationssicherheitsanforderungen festzulegen und umzusetzen. + +- **[ISO A.5.18]** Zugriffsrechte sind gemäß der Zugriffssteuerungsrichtlinie zuzuteilen, zu überprüfen, zu ändern und zu entziehen. + +- **[ISO A.8.2]** Die Zuteilung und Nutzung privilegierter Zugriffsrechte ist einzuschränken und eng zu steuern. + +- **[ISO A.8.3]** Der Zugriff auf Informationen und Anwendungsfunktionen ist gemäß der Zugriffssteuerungsrichtlinie einzuschränken. + +- **[ISO A.8.18]** Die Nutzung von Hilfsprogrammen, die System- und Anwendungskontrollen umgehen können, ist einzuschränken und streng zu steuern. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Zugriffsrechte werden nach dem Minimalprinzip (need-to-know/least privilege) rollenbasiert (RBAC) über das zentrale Verzeichnis ({{TOOL_IAM}}) vergeben; Antrag, fachliche Prüfung und Genehmigung erfolgen im {{TOOL_TICKET}} (siehe {{LINK:VA-03}}). Rechte werden bei Änderung/Wegfall aktualisiert bzw. entzogen und mindestens {{RECERT_FREQ}} rezertifiziert (BL-IAM-05), auch in Kundensystemen; Standardkonten erhalten keine privilegierten Rechte. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf werden Zugriffsrechte durch den verantwortlichen internen Information Officer genehmigt. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf werden Informationen inhaltsverschlüsselt gespeichert (Schutz auch vor privilegierten Nutzern) und Zugriffsrechte in kürzeren Abständen (z. B. quartalsweise) überprüft.{{/if}} +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_IT_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Technische Umsetzung IAM | +| Fachbereiche | Freigabe von Berechtigungen | +| {{ROLE_ISB}} | Überwachung | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_IT_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-03}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R02}}, {{LINK:R05}}, {{LINK:R10}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md b/seed/isms-vorlagenpaket-v2/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md new file mode 100644 index 0000000..15fd524 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R09_Kryptografie-und-Uebertragungsrichtlinie.md @@ -0,0 +1,156 @@ +# Richtlinie Kryptografie- und Übertragungsrichtlinie + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt kryptografische Verfahren, Schlüsselverwaltung und Schutz bei der Informationsübertragung. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Einsatz kryptografischer Verfahren + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.24{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Alle eingesetzten kryptografischen Verfahren (z. B. Verschlüsselung, Signatur, Hash-Algorithmen, Protokolle) bieten die im jeweiligen Anwendungsfeld erforderliche Sicherheit nach anerkanntem Industriestandard, soweit rechtlich möglich. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Konzept für den Einsatz von Kryptografie ist definiert und umgesetzt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) sind bestimmt und erfüllt. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.24]** Regeln für die wirksame Nutzung von Kryptographie einschließlich Schlüsselverwaltung sind festzulegen und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Zulässige Verfahren und Schlüssellängen nach BL-CRY-02 ({{CRYPTO_ALGO}}) entsprechen dem anerkannten Industriestandard und sind vorgegeben; veraltete Verfahren sind untersagt. Ein Kryptokonzept ist dokumentiert (siehe {{LINK:VA-07}}), Schlüssel werden über ihren Lebenszyklus sicher verwaltet (BL-CRY-05). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind Anforderungen an die Schlüsselhoheit (insbesondere bei externer Verarbeitung) bestimmt und erfüllt. +{{/if}} + +### 3.2 Schutz bei der Informationsübertragung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.14{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die zur Informationsübertragung genutzten Netzdienste sind identifiziert und dokumentiert. + +- **[MUSS]** Richtlinien und Verfahren entsprechend den Klassifizierungsanforderungen für die Nutzung von Netzdiensten sind definiert und umgesetzt. + +- **[MUSS]** Maßnahmen zum Schutz übertragener Inhalte gegen unbefugten Zugriff sind umgesetzt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Maßnahmen zur Sicherstellung korrekter Adressierung und korrekter Informationsübertragung sind umgesetzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Elektronischer Datenaustausch erfolgt mittels Inhalts- oder Transportverschlüsselung entsprechend der jeweiligen Klassifizierung. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Fernzugriffsverbindungen zum Netzwerk der Organisation verfügen über angemessene Sicherheitsmerkmale; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Informationen werden verschlüsselt übertragen (mindestens Transportverschlüsselung) oder durch gleichwertig wirksame Maßnahmen geschützt. (C) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Informationen werden inhaltsverschlüsselt übertragen. (C) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.14]** Regeln, Verfahren und Vereinbarungen zur sicheren Übertragung von Informationen für alle genutzten Übertragungswege sind festzulegen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Genutzte Netzdienste sind im Netz-/Netzdienste-Register ({{LINK:REG-NET}}) identifiziert und dokumentiert; Richtlinien/Verfahren entsprechend der Klassifizierung sind umgesetzt. Informationen werden schutzbedarfsgerecht bei der Übertragung geschützt (mindestens {{TLS_MIN}}, BL-CRY-01), korrekte Adressierung sichergestellt und Fernzugriffe abgesichert; Regeln für E-Mail-/Dateiverschlüsselung sind definiert (BL-CRY-04, Krypto-/Schlüsselverwaltung siehe {{LINK:VA-07}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf werden Informationen mindestens transportverschlüsselt oder gleichwertig geschützt übertragen; {{#if FLAG_VERY_HIGH_PROTECTION}}bei sehr hohem Schutzbedarf erfolgt eine Inhaltsverschlüsselung.{{/if}} +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_IT_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Verfahren/Schlüssel | +| {{ROLE_ISB}} | Zulässige Algorithmen | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_IT_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-07}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R08}}, {{LINK:R10}}, {{LINK:R12}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R10_Betriebssicherheit.md b/seed/isms-vorlagenpaket-v2/richtlinien/R10_Betriebssicherheit.md new file mode 100644 index 0000000..1d0b57a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R10_Betriebssicherheit.md @@ -0,0 +1,598 @@ +# Richtlinie Betriebssicherheit + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt den sicheren IT-Betrieb: Change, Umgebungstrennung, Malware-Schutz, Protokollierung, Schwachstellen, technische Prüfung, Netzwerksicherheit sowie Datensicherung. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Änderungsmanagement (Change) + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.9, A.8.32{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Informationssicherheitsanforderungen für Änderungen an Organisation, Geschäftsprozessen und IT-Systemen sind bestimmt und erfüllt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein formales Genehmigungsverfahren ist etabliert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die möglichen Auswirkungen von Änderungen auf die Informationssicherheit werden bewertet. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Änderungen mit Auswirkung auf die Informationssicherheit werden geplant und getestet. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Verfahren zum Rückfall (Fallback) in Fehlerfällen werden berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Einhaltung der Informationssicherheitsanforderungen wird während und nach den Änderungen überprüft. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.9]** Konfigurationen von Hardware, Software, Diensten und Netzen sind festzulegen, zu dokumentieren, umzusetzen, zu überwachen und zu überprüfen. + +- **[ISO A.8.32]** Änderungen an informationsverarbeitenden Einrichtungen und Systemen sind einem Änderungsmanagement zu unterziehen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Änderungen durchlaufen ein formales Change-Verfahren (siehe {{LINK:VA-04}}) mit Antrag, Auswirkungs-/Risikobewertung, Planung, Test, Genehmigung, Rollback-Plan und Dokumentation im {{TOOL_TICKET}} (BL-OPS-09); Informationssicherheitsanforderungen sind bestimmt und erfüllt. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf wird die Einhaltung der Informationssicherheitsanforderungen während und nach der Änderung verifiziert. +{{/if}} + +### 3.2 Trennung von Entwicklungs-, Test- und Produktivsystemen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.31{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die IT-Systeme wurden einer Risikobewertung unterzogen, um die Notwendigkeit ihrer Trennung in Entwicklungs-, Test- und Produktivsysteme zu bestimmen. + +- **[MUSS]** Eine Segmentierung ist auf Basis der Ergebnisse der Risikoanalyse umgesetzt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Anforderungen an Entwicklungs- und Testumgebungen sind bestimmt und erfüllt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.31]** Entwicklungs-, Test- und Produktionsumgebungen sind zu trennen und zu schützen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Auf Basis einer Risikobewertung sind Entwicklung, Test und Produktion getrennt betrieben und segmentiert; Anforderungen an Entwicklungs-/Testumgebungen sind bestimmt und erfüllt, Produktivdaten werden dort nur anonymisiert/pseudonymisiert genutzt. + +### 3.3 Schutz vor Schadsoftware + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.7, A.8.23{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Anforderungen zum Schutz vor Schadsoftware sind bestimmt. + +- **[MUSS]** Technische und organisatorische Maßnahmen zum Schutz vor Schadsoftware sind definiert und umgesetzt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Unnötige Netzwerkdienste sind deaktiviert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Der Zugriff auf Netzwerkdienste ist durch geeignete Schutzmaßnahmen auf das Notwendige beschränkt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Schutzsoftware gegen Schadsoftware ist installiert und wird regelmäßig automatisch aktualisiert (z. B. Virenscanner). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Empfangene Dateien und Software werden vor der Ausführung automatisch auf Schadsoftware geprüft (On-Access-Scan). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Der gesamte Datenbestand aller Systeme wird regelmäßig auf Schadsoftware geprüft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Über zentrale Gateways übertragene Daten (z. B. E-Mail, Internet, Fremdnetze) werden automatisch durch Schutzsoftware geprüft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Maßnahmen, die verhindern, dass Schutzsoftware durch Nutzer deaktiviert oder verändert wird, sind definiert und umgesetzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Für IT-Systeme ohne Schutzsoftware sind alternative Maßnahmen umgesetzt (z. B. besondere Resilienz, wenige Dienste, keine aktiven Nutzer, Netzisolation). +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.7]** Schutz vor Schadsoftware ist umzusetzen und durch angemessene Awareness der Benutzer zu unterstützen. + +- **[ISO A.8.23]** Der Zugriff auf externe Webseiten ist zu steuern, um die Exposition gegenüber schädlichen Inhalten zu reduzieren. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Malware-Schutz ist über {{TECH_MALWARE}} auf allen Endpunkten und Servern umgesetzt (BL-OPS-03); Signaturen/Engines aktualisieren sich {{MALWARE_UPDATE}}, On-Access- und regelmäßige Vollscans sowie Gateway-Prüfungen (E-Mail/Internet) sind aktiv. Unnötige Netzwerkdienste sind deaktiviert, der Zugriff ist beschränkt, das Deaktivieren der Schutzsoftware ist unterbunden; für Systeme ohne Schutzsoftware greifen alternative Maßnahmen (Isolation). + +### 3.4 Protokollierung und Auswertung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.15, A.8.16{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Informationssicherheitsanforderungen an den Umgang mit Ereignisprotokollen sind bestimmt und erfüllt. + +- **[MUSS]** Sicherheitsrelevante Anforderungen an die Protokollierung von Aktivitäten von Administratoren und Nutzern sind bestimmt und erfüllt. + +- **[MUSS]** Die eingesetzten IT-Systeme werden hinsichtlich der Notwendigkeit der Protokollierung bewertet. + +- **[MUSS]** Bei Nutzung externer IT-Dienste werden Informationen zu den Überwachungsmöglichkeiten eingeholt und in der Bewertung berücksichtigt. + +- **[MUSS]** Ereignisprotokolle werden regelmäßig auf Richtlinienverstöße und auffällige Probleme geprüft, unter Einhaltung der zulässigen rechtlichen und organisatorischen Vorgaben. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Verfahren zur Eskalation relevanter Ereignisse an die verantwortliche Stelle ist definiert und etabliert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ereignisprotokolle (Inhalt und Metadaten) sind gegen Veränderung geschützt (z. B. durch eine dedizierte Umgebung). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine angemessene Überwachung und Aufzeichnung aller informationssicherheitsrelevanten Aktionen im Netzwerk ist etabliert. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Sicherheitsrelevante Anforderungen an den Umgang mit Ereignisprotokollen, z. B. vertragliche Anforderungen, sind bestimmt und umgesetzt. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Ereignisse zu Auf- und Abbau von Fernzugriffssitzungen (z. B. Fernwartung) werden protokolliert. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Protokollierung jedes Zugriffs auf Daten mit sehr hohem Schutzbedarf, soweit technisch machbar und rechtlich/organisatorisch zulässig. (C, I) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.15]** Protokolle über Aktivitäten, Ausnahmen, Fehler und Ereignisse sind zu erzeugen, zu speichern, zu schützen und auszuwerten. + +- **[ISO A.8.16]** Netze, Systeme und Anwendungen sind auf anomales Verhalten zu überwachen und mögliche Vorfälle zu bewerten. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Sicherheitsrelevante Ereignisse (inkl. Administrator-/Nutzeraktivitäten) werden nach bestimmten und bewerteten Anforderungen zentral über {{TECH_SIEM}} protokolliert und regelmäßig auf Verstöße ausgewertet (BL-OPS-04); bei externen Diensten werden Überwachungsmöglichkeiten berücksichtigt. Protokolle sind manipulationsgeschützt, Aufbewahrung {{LOG_RETENTION}}, ein Eskalationsverfahren ist etabliert (siehe {{LINK:VA-13}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind zusätzliche (z. B. vertragliche) Protokollanforderungen umgesetzt und Fernzugriffssitzungen werden protokolliert. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf wird jeder Zugriff auf entsprechende Daten protokolliert, soweit technisch/rechtlich zulässig.{{/if}} +{{/if}} + +### 3.5 Umgang mit Schwachstellen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.5{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.8{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Informationen über technische Schwachstellen der eingesetzten IT-Systeme werden erhoben (z. B. Herstellerinfos, System-Audits, CVE-Datenbank). + +- **[MUSS]** Potenziell betroffene IT-Systeme und Software werden identifiziert und das durch die Schwachstelle verursachte Risiko wird bewertet. + +- **[MUSS]** Risiken aus Schwachstellen werden behandelt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein angemessenes Patch-Management ist definiert und umgesetzt (z. B. Patch-Test und -Installation). +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Risikominimierende Maßnahmen werden bei Bedarf umgesetzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die erfolgreiche Installation von Patches wird in geeigneter Weise verifiziert. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.8]** Informationen über technische Schwachstellen sind zu beschaffen, die Betroffenheit zu bewerten und geeignete Maßnahmen zu ergreifen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Schwachstelleninformationen werden erhoben (Herstellerinfos, CVE, Scans BL-OPS-02), betroffene Systeme identifiziert, das Risiko bewertet und nach BL-OPS-01 risikoorientiert über Patch-/Change-Management (siehe {{LINK:VA-06}}) behandelt (kritisch {{PATCH_SLA_CRIT}}); die erfolgreiche Installation wird verifiziert und im {{TOOL_TICKET}} nachverfolgt, risikominimierende Maßnahmen greifen bei Bedarf. + +### 3.6 Technische Überprüfung von IT-Systemen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.6{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.34{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Anforderungen an die Prüfung (Audit) von IT-Systemen oder -Diensten sind bestimmt. + +- **[MUSS]** Der Umfang der Systemprüfung wird rechtzeitig festgelegt. + +- **[MUSS]** System- oder Dienstprüfungen werden mit Betreiber und Nutzern der IT-Systeme/-Dienste abgestimmt. + +- **[MUSS]** Die Ergebnisse von System-/Dienstprüfungen werden nachvollziehbar gespeichert und der zuständigen Leitung berichtet. + +- **[MUSS]** Aus den Ergebnissen werden Maßnahmen abgeleitet und in angemessener Frist umgesetzt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** System- und Dienstprüfungen werden unter Berücksichtigung möglicher Sicherheitsrisiken (z. B. Störungen) geplant. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Regelmäßige System- oder Dienstprüfungen werden durchgeführt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Innerhalb einer angemessenen Frist nach Abschluss der Prüfung wird ein Bericht erstellt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Für kritische IT-Systeme/-Dienste wurden zusätzliche Prüfanforderungen identifiziert und werden erfüllt (z. B. dienstspezifische Tests/Werkzeuge und/oder manuelle Penetrationstests, risikobasierte Intervalle). (A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** IT-Systeme und -Dienste werden regelmäßig auf Schwachstellen gescannt. Für nicht scanbare Systeme/Dienste sind geeignete Schutzmaßnahmen umzusetzen. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.34]** Audit-Tests und ähnliche Prüftätigkeiten an Produktivsystemen sind zu planen und zu vereinbaren, um Beeinträchtigungen zu vermeiden. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Anforderungen und Umfang technischer Prüfungen sind bestimmt und mit Betreibern/Nutzern abgestimmt; Systeme werden nach Härtungsvorgaben (BL-OPS-07, z. B. CIS-Benchmarks) konfiguriert und risikoorientiert geprüft (siehe {{LINK:VA-06}}). Ergebnisse werden nachvollziehbar gespeichert, der Leitung berichtet und Maßnahmen fristgerecht umgesetzt. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf werden für kritische Systeme zusätzliche Prüfungen (Penetrationstests {{PENTEST_FREQ}}, BL-OPS-08) durchgeführt. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf werden Systeme regelmäßig auf Schwachstellen gescannt bzw. nicht scanbare durch geeignete Maßnahmen geschützt.{{/if}} +{{/if}} + +### 3.7 Netzwerksicherheit + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.7{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.20, A.8.22{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und erfüllt. + +- **[MUSS]** Anforderungen an die Netzsegmentierung sind bestimmt und erfüllt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Verfahren für das Management und die Steuerung von Netzwerken sind definiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Für eine risikobasierte Netzsegmentierung werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Erweiterte Anforderungen an das Management und die Steuerung von Netzwerken sind bestimmt und umgesetzt. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.20]** Netze und Netzwerkgeräte sind zu sichern, zu verwalten und zu steuern, um Informationen zu schützen. + +- **[ISO A.8.22]** Gruppen von Informationsdiensten, Nutzern und Systemen sind in Netzen zu segmentieren. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Das Netzwerk ist nach Schutzbedarf risikobasiert segmentiert (BL-NET-01), zugangskontrolliert und nach außen über Firewall (Default-Deny, BL-NET-02) abgesichert; Management-/Steuerungsverfahren und ein aktueller Netzplan/Segmentierungskonzept werden im Netz-/Netzdienste-Register ({{LINK:REG-NET}}) gepflegt.{{#if FLAG_OT_USED}} Produktions-/OT-Netze sind von Office-Netzen getrennt und besonders abgesichert.{{/if}} + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf sind erweiterte Anforderungen an Netzmanagement und -steuerung bestimmt und umgesetzt. +{{/if}} + +### 3.8 Datensicherung und Wiederherstellung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.2.9{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.13{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Backup-Konzepte existieren für relevante IT-Systeme. Angemessene Schutzmaßnahmen für Vertraulichkeit, Integrität und Verfügbarkeit der Datensicherungen werden berücksichtigt. + +- **[MUSS]** Wiederherstellungskonzepte existieren für relevante IT-Dienste. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Für jeden relevanten IT-Dienst existiert ein Backup- und Wiederherstellungskonzept. Abhängigkeiten zwischen IT-Diensten und die Reihenfolge der Wiederherstellung werden berücksichtigt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Backup- und Wiederherstellungskonzepte werden methodisch in regelmäßigen Abständen überprüft. (A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die grundsätzliche Wiederherstellbarkeit wird berücksichtigt und getestet (z. B. Stichprobentests, Testsysteme). (I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** (Zusätzliche) Backups werden über Offline-Verfahren, unveränderliche (immutable) Backups oder eine isolierte IAM-Lösung durchgeführt. (I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Wiederherstellungsverfahren werden methodisch in regelmäßigen Abständen technisch getestet. (I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Geografische Redundanz wird in Backup- und Wiederherstellungskonzepten berücksichtigt. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.13]** Sicherungskopien von Informationen, Software und Systemen sind gemäß Sicherungskonzept zu erstellen und regelmäßig zu testen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Backup- und Wiederherstellungskonzepte für relevante IT-Dienste bestehen (Schutz von Vertraulichkeit/Integrität/Verfügbarkeit, Abhängigkeiten und Reihenfolge berücksichtigt); Sicherung erfolgt nach Schema {{BACKUP_SCHEME}} über {{TECH_BACKUP}} (BL-OPS-05), Aufbewahrung {{BACKUP_RETENTION}}, Wiederherstellung geregelt und getestet (siehe {{LINK:VA-05}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf werden Konzepte methodisch überprüft und die Wiederherstellbarkeit getestet. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf erfolgen zusätzliche Offline-/immutable-Backups, methodische technische Restore-Tests und geografische Redundanz.{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.9 Bedrohungsinformationen + +*Anforderungsbezug:* ISO/IEC 27001 A.5.7 + +**Anforderung** + + +- **[ISO A.5.7]** Informationen über Bedrohungen sind zu sammeln und auszuwerten, um Bedrohungsinformationen (Threat Intelligence) zu erzeugen und zu nutzen. + +**Umsetzung bei {{ORG_NAME}}** + + +Informationen über Bedrohungen werden regelmäßig aus benannten Quellen ({{THREAT_INTEL_SOURCES}}) bezogen und von {{ROLE_IT_LEAD}} auf Relevanz für die eigenen Systeme und Dienste bewertet. Relevante Erkenntnisse führen zu Maßnahmen im Schwachstellen- und Patchmanagement ({{LINK:VA-06}}), zu Anpassungen der Überwachung ({{LINK:VA-13}}) oder zu einer erneuten Risikobeurteilung. Bewertung und abgeleitete Maßnahmen werden im {{TOOL_TICKET}} dokumentiert. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.10 Dokumentierte Betriebsabläufe + +*Anforderungsbezug:* ISO/IEC 27001 A.5.37 + +**Anforderung** + + +- **[ISO A.5.37]** Betriebsabläufe für informationsverarbeitende Einrichtungen sind zu dokumentieren und den betroffenen Personen bereitzustellen. + +**Umsetzung bei {{ORG_NAME}}** + + +Betriebsabläufe für informationsverarbeitende Einrichtungen sind dokumentiert und den ausführenden Personen zugänglich. Abgedeckt sind Inbetriebnahme und Konfiguration, Betrieb und Überwachung, Datensicherung, Behandlung von Störungen, Wartung sowie Außerbetriebnahme. Die Dokumentation wird bei Änderungen über das Änderungsmanagement (BL-OPS-09) aktualisiert und mindestens {{POLICY_REVIEW_CYCLE}} auf Aktualität geprüft. Verantwortlich: {{ROLE_IT_LEAD}}. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.11 Kapazitätssteuerung + +*Anforderungsbezug:* ISO/IEC 27001 A.8.6 + +**Anforderung** + + +- **[ISO A.8.6]** Ressourcen sind zu überwachen und die Kapazität ist an den aktuellen und erwarteten Bedarf anzupassen. + +**Umsetzung bei {{ORG_NAME}}** + + +Die Auslastung der maßgeblichen Ressourcen — Rechenleistung, Arbeitsspeicher, Speicherplatz, Netzbandbreite, Lizenzen sowie personelle Kapazität im IT-Betrieb — wird {{CAPACITY_REVIEW_FREQ}} überwacht (BL-OPS-11). Überschrittene Schwellenwerte lösen eine Meldung aus; der künftige Bedarf wird bei Projekten und wesentlichen Änderungen berücksichtigt. Kapazitätsengpässe mit Auswirkung auf die Verfügbarkeitsanforderungen werden als Risiko erfasst und behandelt. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.12 Verhinderung von Datenabfluss + +*Anforderungsbezug:* ISO/IEC 27001 A.8.12 + +**Anforderung** + + +- **[ISO A.8.12]** Maßnahmen zur Verhinderung von Datenlecks sind auf Systeme, Netze und Geräte anzuwenden, die sensible Informationen verarbeiten. + +**Umsetzung bei {{ORG_NAME}}** + + +Für Systeme, Netze und Geräte, die schutzbedürftige Informationen verarbeiten, sind Maßnahmen gegen unbefugten Abfluss umgesetzt (BL-OPS-12); abgedeckt sind mindestens {{DLP_SCOPE}}. Die Maßnahmen richten sich nach der Klassifizierung ({{LINK:R02}}): Regeln zur Weitergabe, Kontrolle der Übertragungswege, Beschränkung von Wechseldatenträgern (BL-EP-03) sowie Protokollierung und Auswertung auffälliger Übertragungen (BL-OPS-04). Erkannte Verstöße werden als Sicherheitsereignis behandelt ({{LINK:VA-01}}); bei personenbezogener Auswertung werden Mitbestimmungsrechte gewahrt. + +{{/if}} + + +{{#if FLAG_FW_ISO27001}} + +### 3.13 Uhrzeitsynchronisation + +*Anforderungsbezug:* ISO/IEC 27001 A.8.17 + +**Anforderung** + + +- **[ISO A.8.17]** Die Uhren der Systeme sind auf zugelassene Zeitquellen zu synchronisieren. + +**Umsetzung bei {{ORG_NAME}}** + + +Die Systemuhren aller protokollierenden Systeme werden auf {{NTP_SOURCES}} synchronisiert (BL-OPS-10). Abweichungen werden überwacht und gemeldet. Eine einheitliche Zeitbasis und Zeitzone ist Voraussetzung für die Auswertbarkeit der Protokolle ({{LINK:VA-13}}) und für die Beweissicherung bei Vorfällen. + +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_IT_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Sicherer IT-Betrieb | +| {{ROLE_ISB}} | Überwachung | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_IT_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-04}}, {{LINK:VA-05}}, {{LINK:VA-06}}, {{LINK:VA-13}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R04}}, {{LINK:R08}}, {{LINK:R11}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md b/seed/isms-vorlagenpaket-v2/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md new file mode 100644 index 0000000..87dc142 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R11_Sichere-Systembeschaffung-und-Entwicklung.md @@ -0,0 +1,219 @@ +# Richtlinie Sichere Systembeschaffung und Entwicklung + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Informationssicherheit bei Beschaffung und Entwicklung, Anforderungen an Netzdienste sowie Rückgabe und sichere Löschung. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Sicherheit bei Beschaffung und Entwicklung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.4, A.8.25, A.8.26, A.8.27, A.8.28, A.8.29, A.8.30, A.8.33{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die mit Design und Entwicklung eines IT-Dienstes verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt. + +- **[MUSS]** Die mit Beschaffung oder Erweiterung von IT-Diensten und -Komponenten verbundenen Informationssicherheitsanforderungen sind bestimmt und berücksichtigt. + +- **[MUSS]** Informationssicherheitsanforderungen im Zusammenhang mit Änderungen an entwickelten IT-Diensten werden berücksichtigt. + +- **[MUSS]** Systemabnahmetests werden unter Berücksichtigung der Informationssicherheitsanforderungen durchgeführt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Anforderungsspezifikationen werden erstellt; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Anforderungsspezifikationen werden gegen die Informationssicherheitsanforderungen geprüft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Der IT-Dienst wird vor Produktivnutzung auf Einhaltung der Spezifikationen geprüft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Nutzung von Produktivdaten zu Testzwecken wird soweit möglich vermieden (ggf. Anonymisierung/Pseudonymisierung); dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Testsysteme erhalten Schutzmaßnahmen vergleichbar zur Produktivumgebung, wenn Produktivdaten für Tests genutzt werden. +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Die Sicherheit zweckgebauter oder wesentlich angepasster Software wird bei Inbetriebnahme, bei wesentlichen Änderungen oder regelmäßig getestet (z. B. Penetrationstest). (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.4]** Der Lese- und Schreibzugriff auf Quellcode, Entwicklungswerkzeuge und Softwarebibliotheken ist angemessen zu steuern. + +- **[ISO A.8.25]** Regeln für einen sicheren Entwicklungslebenszyklus von Software und Systemen sind festzulegen und anzuwenden. + +- **[ISO A.8.26]** Informationssicherheitsanforderungen sind bei Entwicklung oder Beschaffung von Anwendungen zu ermitteln, zu spezifizieren und zu berücksichtigen. + +- **[ISO A.8.27]** Grundsätze für die Entwicklung sicherer Systeme sind festzulegen, zu dokumentieren und anzuwenden. + +- **[ISO A.8.28]** Grundsätze für sichere Programmierung sind auf die Softwareentwicklung anzuwenden. + +- **[ISO A.8.29]** Sicherheitstests sind in den Entwicklungs- und Abnahmeprozess zu integrieren. + +- **[ISO A.8.30]** Ausgelagerte Systementwicklung ist zu steuern, zu überwachen und zu überprüfen. + +- **[ISO A.8.33]** Testinformationen sind sorgfältig auszuwählen, zu schützen und zu verwalten. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Informationssicherheitsanforderungen sind fester Bestandteil von Design, Beschaffung, Erweiterung und Änderung von IT-Diensten (Security by Design); Anforderungsspezifikation, Prüfung und Abnahmetests unter Sicherheitsaspekten erfolgen nach dem Verfahren Sichere Beschaffung/Entwicklung & Abnahme ({{LINK:VA-16}}); Produktivsetzung erst nach Prüfung im {{TOOL_TICKET}}. Produktivdaten in Tests werden vermieden/anonymisiert, Testsysteme angemessen geschützt.{{#if FLAG_DEV_INHOUSE}} Für die Eigenentwicklung gelten Secure-Coding-Vorgaben mit Code-Reviews und automatisierten Sicherheitstests (SAST/Dependency-Scan) gemäß {{LINK:VA-16}}.{{/if}} + +{{#if FLAG_ELEVATED_PROTECTION}} + +{{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf wird die Sicherheit zweckgebauter oder wesentlich angepasster Software bei Inbetriebnahme, bei wesentlichen Änderungen oder regelmäßig getestet (Penetrationstest).{{/if}} +{{/if}} + +### 3.2 Anforderungen an Netzdienste + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.8.21{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Anforderungen an die Informationssicherheit von Netzdiensten sind bestimmt und erfüllt. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Verfahren zur Absicherung und Nutzung von Netzdiensten ist definiert und umgesetzt. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Anforderungen werden in Form von SLAs vereinbart. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Angemessene Redundanzlösungen sind umgesetzt. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Verfahren zur Überwachung der Qualität des Netzverkehrs (z. B. Traffic-Flow-Analysen, Verfügbarkeitsmessungen) sind definiert und werden durchgeführt. (A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.8.21]** Sicherheitsmechanismen, Dienstgüten und Anforderungen an Netzwerkdienste sind zu identifizieren, umzusetzen und zu überwachen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Für genutzte Netzdienste (intern/extern) sind Sicherheitsanforderungen bestimmt, in SLAs vereinbart und über ein Verfahren umgesetzt; angemessene Redundanzen bestehen. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf werden Verfahren zur Überwachung der Netzverkehrsqualität (Traffic-Flow-Analysen, Verfügbarkeitsmessungen) definiert und durchgeführt. +{{/if}} + +### 3.3 Rückgabe und sichere Löschung + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.11, A.7.14, A.8.10{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Eine Beschreibung des Beendigungsprozesses ist vorhanden, an Änderungen angepasst und vertraglich geregelt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.11]** Beschäftigte und externe Nutzer haben bei Beendigung des Beschäftigungs-/Vertragsverhältnisses alle in ihrem Besitz befindlichen Assets zurückzugeben. + +- **[ISO A.7.14]** Betriebsmittel mit Speichermedien sind vor Entsorgung oder Wiederverwendung sicher zu bereinigen (Datenlöschung). + +- **[ISO A.8.10]** In Systemen und auf Medien gespeicherte Informationen sind zu löschen, sobald sie nicht mehr benötigt werden. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Rückgabe und sichere Löschung/Vernichtung von Informationen und Assets (bei Vertragsende, Geräteausmusterung) sind nach BL-DEL-01 geregelt, vertraglich vereinbart, an Änderungen angepasst und werden nachgewiesen (Löschprotokoll). + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_IT_LEAD}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_IT_LEAD}} | Beschaffung/Entwicklung | +| {{ROLE_ISB}} | Sicherheitsanforderungen | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_IT_LEAD}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R02}}, {{LINK:R10}}, {{LINK:R12}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md b/seed/isms-vorlagenpaket-v2/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md new file mode 100644 index 0000000..4b5438a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R12_Cloud-KI-und-externe-IT-Dienste.md @@ -0,0 +1,117 @@ +# Richtlinie Cloud-, KI- und externe IT-Dienste + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt den Schutz in ausgelagerten/geteilten externen IT-Diensten (Cloud) sowie beim Einsatz von KI-/GenAI-Diensten. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Schutz in geteilten externen IT-Diensten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 5.3.4{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.23{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Eine wirksame Trennung (z. B. Mandantentrennung) verhindert den Zugriff unbefugter Nutzer anderer Organisationen auf eigene Informationen. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Das Trennungskonzept des Anbieters ist dokumentiert und an Änderungen angepasst; dabei werden die einschlägigen Aspekte berücksichtigt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.23]** Prozesse für Beschaffung, Nutzung, Verwaltung und Beendigung von Cloud-Diensten sind entsprechend den Informationssicherheitsanforderungen festzulegen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Bei geteilten externen IT-Diensten wird eine wirksame Mandantentrennung gefordert und vertraglich zugesichert; das Trennungskonzept des Anbieters wird dokumentiert und bei Änderungen aktualisiert.{{#if FLAG_CLOUD_USED}} Cloud-Dienste werden vor Nutzung bewertet (Schutzbedarf, Datenlokation/EU, Verschlüsselung, Exit) und von {{ROLE_ISB}} freigegeben; die Freigaben werden im Register externe IT-/Cloud-/KI-Dienste ({{LINK:REG-EXT-SERVICES}}) geführt (siehe {{LINK:VA-11}}).{{/if}} + +{{#if FLAG_AI_USED}} +### 3.2 Nutzung von KI-/GenAI-Diensten (Ergänzung R12, nicht ISA) + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Der Einsatz von KI-/GenAI-Diensten ist geregelt; es werden nur freigegebene Dienste genutzt. + +- **[MUSS]** Die Eingabe vertraulicher oder personenbezogener Informationen in nicht freigegebene KI-Dienste ist untersagt; zulässige Datenklassen je Dienst sind definiert. + +- **[MUSS]** Bei freigegebenen KI-Diensten ist geklärt und vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ergebnisse von KI-Diensten werden vor geschäftskritischer Verwendung geprüft (Human-in-the-Loop); der KI-Einsatz wird dokumentiert und regulatorische Anforderungen (z. B. EU AI Act) berücksichtigt. +{{/if}} +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Der Einsatz von KI-/GenAI-Diensten ist geregelt; nur von {{ROLE_ISB}} freigegebene Dienste (geführt im Register externe IT-/Cloud-/KI-Dienste {{LINK:REG-EXT-SERVICES}}) dürfen genutzt werden (siehe {{LINK:VA-11}}). Zulässige Datenklassen je Dienst sind definiert, die Eingabe vertraulicher/personenbezogener Daten in nicht freigegebene Dienste ist untersagt; bei Freigabe ist vertraglich sichergestellt, dass Eingaben nicht zum Training genutzt oder weitergegeben werden. KI-Ergebnisse werden vor kritischer Verwendung geprüft (Human-in-the-Loop), der Einsatz dokumentiert und der EU AI Act berücksichtigt. + +{{/if}} +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Freigabe/Steuerung | +| {{ROLE_IT_LEAD}} | Technische Absicherung | +| Fachbereiche | Nutzung freigegebener Dienste | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-11}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R09}}, {{LINK:R11}}, {{LINK:R13}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md b/seed/isms-vorlagenpaket-v2/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md new file mode 100644 index 0000000..82aab48 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R13_Lieferanten-und-Dienstleistersteuerung.md @@ -0,0 +1,250 @@ +# Richtlinie Lieferanten- und Dienstleistersteuerung + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt Sicherstellung der Informationssicherheit bei Lieferanten, Vertraulichkeitsvereinbarungen und Abgrenzung der Verantwortlichkeiten. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Informationssicherheit bei Lieferanten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 6.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.19, A.5.22{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Auftragnehmer und Partner werden einer Sicherheitsrisikobewertung unterzogen. + +- **[MUSS]** Ein angemessenes Informationssicherheitsniveau wird durch vertragliche Vereinbarungen mit Auftragnehmern und Partnern sichergestellt. + +- **[MUSS]** Sofern zutreffend, werden vertragliche Vereinbarungen mit Auftraggebern/Kunden an Auftragnehmer und Partner weitergegeben. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Auftragnehmer und Partner sind vertraglich verpflichtet, Anforderungen an ein angemessenes Informationssicherheitsniveau an ihre Unterauftragnehmer weiterzugeben. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Leistungsberichte und Dokumente von Auftragnehmern und Partnern werden geprüft. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Es wird nachgewiesen, dass das Informationssicherheitsniveau des Lieferanten dem Schutzbedarf angemessen ist (z. B. geprüfter Fragebogen/Selbstauskunft, Attestierung, Zertifikat, Lieferantenaudit). (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Der Grad der Erfüllung geforderter Nachweise durch den Lieferanten wird dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Einhaltung vertraglicher Vereinbarungen durch den Lieferanten wird geprüft, dokumentiert, regelmäßig und bei Änderungen überprüft und überwacht. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Das angemessene Informationssicherheitsniveau sollte durch ein Drittparteien-Audit (angemessenes TISAX-Label o. Ä.) oder ein angemessenes Lieferantenaudit nachgewiesen werden. Ohne Audit muss die Leitung eine risikobasierte Entscheidung zur Fortführung treffen; ein Nachweis dieser Entscheidung existiert. (C, I, A) +{{/if}} +{{#if FLAG_VERY_HIGH_PROTECTION}} + +- **[SEHR HOCH]** Vertragliche Verpflichtungen gegenüber Kunden zur Transparenz von Lieferkettenrisiken werden erfüllt. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.19]** Prozesse zur Steuerung der Informationssicherheitsrisiken aus Lieferantenbeziehungen sind festzulegen und umzusetzen. + +- **[ISO A.5.22]** Die Informationssicherheit von Lieferantenleistungen ist regelmäßig zu überwachen, zu überprüfen und Änderungen sind zu steuern. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Auftragnehmer/Partner werden einer Sicherheitsrisikobewertung (BL-SUP-01) unterzogen und vertraglich auf ein angemessenes Informationssicherheitsniveau (inkl. Weitergabe an Unterauftragnehmer und Kundenanforderungen) verpflichtet; das Lieferantenverzeichnis wird im ISMS-Tool ({{TOOL_NAME}}) geführt, Leistungsberichte werden geprüft (siehe {{LINK:VA-10}}). + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf wird das Sicherheitsniveau des Lieferanten nachgewiesen (Selbstauskunft/Attest/Zertifikat/Audit) und die Einhaltung dokumentiert, regelmäßig und bei Änderungen überwacht. {{#if FLAG_VERY_HIGH_PROTECTION}}Bei sehr hohem Schutzbedarf erfolgt der Nachweis über ein Drittparteien-Audit (TISAX o. Ä.) oder eine dokumentierte risikobasierte Leitungsentscheidung; Transparenzpflichten zu Lieferkettenrisiken werden erfüllt.{{/if}} +{{/if}} + +### 3.2 Vertraulichkeitsvereinbarungen + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 6.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.20{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die Vertraulichkeitsanforderungen sind bestimmt und erfüllt. + +- **[MUSS]** Anforderungen und Verfahren zur Anwendung von Vertraulichkeitsvereinbarungen sind allen Personen bekannt, die schutzbedürftige Informationen weitergeben. + +- **[MUSS]** Gültige Vertraulichkeitsvereinbarungen werden vor der Weitergabe schutzbedürftiger Informationen abgeschlossen. + +- **[MUSS]** Die Anforderungen und Verfahren zur Nutzung von Vertraulichkeitsvereinbarungen und zum Umgang mit schutzbedürftigen Informationen werden regelmäßig überprüft. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Vorlagen für Vertraulichkeitsvereinbarungen sind vorhanden und auf rechtliche Anwendbarkeit geprüft. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Vertraulichkeitsvereinbarungen umfassen beteiligte Personen/Organisationen, Art der Informationen, Gegenstand, Gültigkeitsdauer und Verantwortlichkeiten der verpflichteten Partei. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Vertraulichkeitsvereinbarungen enthalten Regelungen zum Umgang mit schutzbedürftigen Informationen über die Vertragsbeziehung hinaus. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Möglichkeiten zum Nachweis der Einhaltung (z. B. Prüfung durch unabhängige Dritte oder Auditrechte) sind definiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Ein Prozess zur Überwachung der Gültigkeitsdauer temporärer Vertraulichkeitsvereinbarungen und zur rechtzeitigen Verlängerung ist definiert und umgesetzt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.20]** Relevante Informationssicherheitsanforderungen sind mit jedem Lieferanten zu vereinbaren und vertraglich festzuhalten. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Vertraulichkeitsanforderungen sind bestimmt und bekannt; vor Weitergabe schutzbedürftiger Informationen werden gültige NDAs auf Basis geprüfter Standardvorlagen (Ablauf siehe {{LINK:VA-10}}) (mit Parteien, Informationsart, Gegenstand, Gültigkeit, Verantwortlichkeiten und nachvertraglichen Regelungen) abgeschlossen und im ISMS-Tool hinterlegt. Anforderungen/Verfahren und Gültigkeitsdauern werden regelmäßig überwacht, Nachweismöglichkeiten sind definiert. + +### 3.3 Abgrenzung der Verantwortlichkeiten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 6.1.3{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.21{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Die betroffenen IT-Dienste sind identifiziert. + +- **[MUSS]** Die für den IT-Dienst relevanten Sicherheitsanforderungen sind bestimmt. + +- **[MUSS]** Die für die Umsetzung der Anforderung verantwortliche Organisation ist definiert und sich ihrer Verantwortung bewusst. + +- **[MUSS]** Mechanismen für geteilte Verantwortlichkeiten sind spezifiziert und umgesetzt. + +- **[MUSS]** Die verantwortliche Organisation erfüllt ihre jeweiligen Verantwortlichkeiten. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Bei IT-Diensten ist die Konfiguration auf Basis der notwendigen Sicherheitsanforderungen konzipiert, umgesetzt und dokumentiert. +{{/if}} +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Das verantwortliche Personal ist angemessen geschult. +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Eine Liste der betroffenen IT-Dienste und der jeweils verantwortlichen IT-Dienstleister existiert. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Anwendbarkeit der ISA-Controls wurde bewertet und dokumentiert. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Dienstkonfiguration ist in die regelmäßigen Sicherheitsbewertungen einbezogen. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Es wird nachgewiesen, dass die IT-Dienstleister ihre Verantwortung erfüllen. (C, I, A) +{{/if}} +{{#if FLAG_HIGH_PROTECTION}} + +- **[HOCH]** Die Integration in lokale Schutzmaßnahmen (z. B. sichere Authentifizierungsmechanismen) ist etabliert und dokumentiert. (C, I, A) +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.21]** Prozesse zum Umgang mit Informationssicherheitsrisiken in der IKT-Produkt- und Dienstleistungs-Lieferkette sind festzulegen und umzusetzen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Betroffene IT-Dienste und ihre Sicherheitsanforderungen sind identifiziert; Verantwortlichkeiten zwischen der Organisation und externen IT-Dienstleistern (inkl. Mechanismen für geteilte Verantwortung) sind definiert, bekannt und werden erfüllt (siehe {{LINK:VA-10}}); betroffene IT-Dienste und Dienstleister sind im Register externe IT-/Cloud-/KI-Dienste ({{LINK:REG-EXT-SERVICES}}) geführt. Die Konfiguration ist anforderungsbasiert umgesetzt und dokumentiert, das Personal geschult. + +{{#if FLAG_ELEVATED_PROTECTION}} + +Bei hohem Schutzbedarf existiert eine Liste der IT-Dienste und verantwortlichen Dienstleister, die Anwendbarkeit der ISA-Controls ist bewertet/dokumentiert, die Dienstkonfiguration ist Teil regelmäßiger Sicherheitsbewertungen, die Verantwortungserfüllung wird nachgewiesen und die Integration in lokale Schutzmaßnahmen ist dokumentiert. +{{/if}} + +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Lieferantensteuerung | +| Einkauf | Vertragliche Einbindung | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Zugehörige Verfahren: {{LINK:VA-10}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:R01}}, {{LINK:R12}} + + diff --git a/seed/isms-vorlagenpaket-v2/richtlinien/R14_Compliance-und-Datenschutz.md b/seed/isms-vorlagenpaket-v2/richtlinien/R14_Compliance-und-Datenschutz.md new file mode 100644 index 0000000..9fcb527 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/richtlinien/R14_Compliance-und-Datenschutz.md @@ -0,0 +1,129 @@ +# Richtlinie Compliance und Datenschutz + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Richtlinie | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Verantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + +## 1. Zweck + +Diese Richtlinie regelt die Einhaltung regulatorischer/vertraglicher Vorgaben sowie den Schutz personenbezogener Daten. Sie konkretisiert die Informationssicherheitsleitlinie ({{LINK:L00}}) und dient der Erfüllung der Anforderungen des VDA ISA 2027. + +## 2. Geltungsbereich + +Diese Richtlinie gilt innerhalb des definierten ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Anforderungen und Umsetzung + +> Aufbau je Abschnitt: **Anforderung** (1:1 aus VDA ISA; [MUSS]/[SOLL] und – bei entsprechendem Schutzbedarf – [HOCH]/[SEHR HOCH]) und **Umsetzung bei {{ORG_NAME}}** (gebündelt, anzupassen wo erforderlich). + +### 3.1 Regulatorische und vertragliche Compliance + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 7.1.1{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.31, A.5.32, A.5.33{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Rechtliche, regulatorische und vertragliche Vorgaben mit Relevanz für die Informationssicherheit werden regelmäßig bestimmt. + +- **[MUSS]** Richtlinien zur Einhaltung der Vorgaben sind definiert, umgesetzt und den verantwortlichen Personen kommuniziert. +{{#if FLAG_INCLUDE_SHOULD}} + +- **[SOLL]** Die Integrität von Aufzeichnungen entsprechend rechtlichen, regulatorischen und vertraglichen Vorgaben sowie Geschäftsanforderungen wird berücksichtigt. +{{/if}} +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.31]** Rechtliche, gesetzliche, regulatorische und vertragliche Anforderungen an die Informationssicherheit sind zu identifizieren, zu dokumentieren und aktuell zu halten. + +- **[ISO A.5.32]** Geeignete Verfahren zum Schutz geistiger Eigentumsrechte sind umzusetzen. + +- **[ISO A.5.33]** Aufzeichnungen sind vor Verlust, Zerstörung, Fälschung sowie unbefugtem Zugriff und unbefugter Veröffentlichung zu schützen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Relevante rechtliche, regulatorische und vertragliche Anforderungen werden regelmäßig bestimmt und in einem Compliance-/Rechtsregister im ISMS-Tool ({{TOOL_NAME}}) erfasst; Richtlinien zur Einhaltung sind definiert, umgesetzt und den Verantwortlichen kommuniziert, die Integrität von Aufzeichnungen wird berücksichtigt. + +{{#if FLAG_PERSONAL_DATA}} +### 3.2 Schutz personenbezogener Daten + + +*Anforderungsbezug:* {{#if FLAG_FW_TISAX}}VDA ISA 7.1.2{{/if}}{{#if FLAG_FW_ISO27001}}{{#if FLAG_FW_TISAX}} · {{/if}}ISO/IEC 27001 A.5.34{{/if}} + + +**Anforderung** + + +{{#if FLAG_FW_TISAX}} +{{#if FLAG_FW_ISO27001}}*Anforderungen nach VDA ISA 2027:*{{/if}} + + +- **[MUSS]** Rechtliche und vertragliche Informationssicherheitsanforderungen an Verfahren und Prozesse bei der Verarbeitung personenbezogener Daten sind bestimmt. + +- **[MUSS]** Regelungen zur Einhaltung rechtlicher und vertraglicher Anforderungen an den Schutz personenbezogener Daten sind definiert und den beteiligten Personen bekannt. + +- **[MUSS]** Prozesse und Verfahren zum Schutz personenbezogener Daten sind im Informationssicherheits-Managementsystem berücksichtigt. +{{/if}} + + +{{#if FLAG_FW_ISO27001}} +{{#if FLAG_FW_TISAX}}*Anforderungen nach ISO/IEC 27001:*{{/if}} + + +- **[ISO A.5.34]** Anforderungen an den Schutz personenbezogener Daten (PII) sind zu identifizieren und gemäß geltenden Vorgaben zu erfüllen. +{{/if}} + + +**Umsetzung bei {{ORG_NAME}}** + + +Rechtliche und vertragliche Anforderungen an die Verarbeitung personenbezogener Daten (DSGVO) sind bestimmt; Regelungen sind definiert, den Beteiligten bekannt und im ISMS berücksichtigt. {{ROLE_DPO}} ist eingebunden, das Verzeichnis der Verarbeitungstätigkeiten wird im ISMS-Tool ({{TOOL_NAME}}) geführt, TOM und Löschkonzepte (BL-DEL-01) sind geregelt; Rechtsregister-Review, Löschfristen und Betroffenenrechte werden nach dem Datenschutz-/Compliance-Pflegeverfahren ({{LINK:VA-18}}) bearbeitet. + +{{/if}} +## 4. Verbindlichkeit + +Diese Richtlinie ist für alle betroffenen Rollen im Geltungsbereich verbindlich. Die Einhaltung wird durch {{ROLE_ISB}} überwacht. + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung in dieser Richtlinie | +|-------|-------------------------------------| +| {{ROLE_ISB}} | Compliance-Register | +| {{ROLE_DPO}} | Datenschutz | + +## 6. Überprüfung und Aktualisierung + +Diese Richtlinie wird mindestens {{REVIEW_CYCLE}} sowie anlassbezogen durch {{ROLE_ISB}} überprüft und durch {{ROLE_MANAGEMENT}} freigegeben. + +## 7. Nachweise + +Die Nachweise werden nicht in diesem Dokument geführt, sondern zentral im Nachweisregister ({{LINK:NACHWEISREGISTER}}) sowie in den zugehörigen Einträgen des ISMS-Tools ({{TOOL_NAME}}). + +## 8. Verwandte Dokumente + +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} +- Nachweisregister: {{LINK:NACHWEISREGISTER}} +- Weitere: {{LINK:L00}}, {{LINK:R03}} + + diff --git a/seed/isms-vorlagenpaket-v2/variables.schema.json b/seed/isms-vorlagenpaket-v2/variables.schema.json new file mode 100644 index 0000000..b84461c --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/variables.schema.json @@ -0,0 +1,379 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ISMS-Vorlagenpaket v2 – Wizard-Variablen (VDA ISA 2027 / Information Security)", + "description": "Single Source of Truth aller Wizard-Variablen. Konvention: UPPER_SNAKE_CASE, Platzhalter {{NAME}}. Feature-Flags steuern {{#if FLAG_X}}-Bloecke. Der Programmierer generiert die Wizard-Eingaben aus diesem Schema.", + "version": "2.0", + "type": "object", + "properties": { + "ORG_NAME": { + "type": "string", + "title": "Organisation (voller Name)", + "example": "Muster GmbH" + }, + "ORG_SHORT": { + "type": "string", + "title": "Organisation (Kurzname)", + "example": "Muster" + }, + "ISMS_SCOPE": { + "type": "string", + "title": "Geltungsbereich (Kurzlabel)", + "example": "IT & Entwicklung Werk Nord" + }, + "ISMS_SCOPE_DESCRIPTION": { + "type": "string", + "title": "Geltungsbereich (Beschreibung)" + }, + "ROLE_MANAGEMENT": { + "type": "string", + "title": "Oberste Leitung", + "default": "Geschäftsführung" + }, + "ROLE_ISB": { + "type": "string", + "title": "Informationssicherheitsbeauftragte(r) / CISO", + "default": "Informationssicherheitsbeauftragte(r) (ISB)" + }, + "ROLE_IT_LEAD": { + "type": "string", + "title": "IT-Leitung", + "default": "IT-Leitung" + }, + "ROLE_HR_LEAD": { + "type": "string", + "title": "Personalleitung", + "default": "Personalleitung" + }, + "ROLE_DPO": { + "type": "string", + "title": "Datenschutzbeauftragte(r)", + "default": "Datenschutzbeauftragte(r) (DSB)" + }, + "DOC_VERSION": { + "type": "string", + "title": "Version", + "default": "1.0" + }, + "DOC_DATE": { + "type": "string", + "title": "Datum", + "format": "date" + }, + "DOC_STATUS": { + "type": "string", + "title": "Status", + "enum": [ + "Entwurf", + "In Freigabe", + "Freigegeben" + ], + "default": "Entwurf" + }, + "TOOL_NAME": { + "type": "string", + "title": "Name des ISMS-Tools", + "default": "ISMS-Tool" + }, + "REVIEW_CYCLE": { + "type": "string", + "title": "Revisionszyklus (Freitext)", + "default": "jährlich" + }, + "TECH_MFA": { + "type": "string", + "title": "MFA-Lösung", + "default": "die eingesetzte MFA-Lösung" + }, + "TECH_MALWARE": { + "type": "string", + "title": "Malware-Schutz-Lösung", + "default": "die eingesetzte Endpoint-Schutzlösung" + }, + "TECH_BACKUP": { + "type": "string", + "title": "Backup-Lösung", + "default": "die eingesetzte Backup-Lösung" + }, + "TECH_SIEM": { + "type": "string", + "title": "Logging/SIEM-Lösung", + "default": "die zentrale Protokollierung" + }, + "TECH_MDM": { + "type": "string", + "title": "MDM-Lösung", + "default": "das eingesetzte MDM" + }, + "TECH_VPN": { + "type": "string", + "title": "VPN/Remote-Access-Lösung", + "default": "VPN" + }, + "TECH_CRYPTO": { + "type": "string", + "title": "Krypto-Vorgabe/Standard", + "default": "aktuelle BSI-/Branchenempfehlungen" + }, + "TOOL_TICKET": { + "type": "string", + "title": "Ticket-/Workflow-System (Dokumentationsort)", + "default": "Ticketsystem" + }, + "TOOL_IAM": { + "type": "string", + "title": "Verzeichnis-/IAM-System", + "default": "Entra ID / Active Directory" + }, + "PW_MIN_LENGTH": { + "type": "string", + "title": "Passwort-Mindestlänge (BL-IAM-01)", + "default": "12" + }, + "PW_COMPLEXITY": { + "type": "string", + "title": "Passwort-Komplexität (BL-IAM-01)", + "default": "Komplexität aus mind. 3 von 4 Zeichenkategorien" + }, + "PW_ROTATION": { + "type": "string", + "title": "Passwort-Rotation (BL-IAM-01)", + "default": "keine feste Zwangsrotation, Wechsel anlassbezogen bei Verdacht" + }, + "MFA_SCOPE": { + "type": "string", + "title": "MFA-Geltungsbereich (BL-IAM-02)", + "default": "alle Fernzugriffe, administrative Zugänge und Cloud-Dienste" + }, + "SESSION_TIMEOUT": { + "type": "string", + "title": "Sitzungs-Timeout (BL-IAM-03)", + "default": "15 Min. Inaktivität (privilegiert), 8 Std. (Standard)" + }, + "ACCOUNT_LOCKOUT": { + "type": "string", + "title": "Kontosperrung (BL-IAM-04)", + "default": "temporäre Sperre nach 10 Fehlversuchen" + }, + "RECERT_FREQ": { + "type": "string", + "title": "Rezertifizierung (BL-IAM-05)", + "default": "halbjährlich" + }, + "TLS_MIN": { + "type": "string", + "title": "Mindest-TLS (BL-CRY-01)", + "default": "TLS 1.2 (Empfehlung TLS 1.3)" + }, + "CRYPTO_ALGO": { + "type": "string", + "title": "Zulässige Algorithmen (BL-CRY-02)", + "default": "AES-256, RSA ≥ 3072 / ECC ≥ 256, SHA-256 oder stärker" + }, + "PATCH_SLA_CRIT": { + "type": "string", + "title": "Patch-SLA kritisch (BL-OPS-01)", + "default": "innerhalb von 72 Stunden" + }, + "PATCH_SLA_HIGH": { + "type": "string", + "title": "Patch-SLA hoch (BL-OPS-01)", + "default": "innerhalb von 14 Tagen" + }, + "PATCH_SLA_STD": { + "type": "string", + "title": "Patch-SLA standard (BL-OPS-01)", + "default": "im regulären monatlichen Patchzyklus" + }, + "VULN_SCAN_FREQ": { + "type": "string", + "title": "Schwachstellenscan (BL-OPS-02)", + "default": "monatlich" + }, + "MALWARE_UPDATE": { + "type": "string", + "title": "Malware-Update (BL-OPS-03)", + "default": "mehrmals täglich automatisch" + }, + "LOG_RETENTION": { + "type": "string", + "title": "Log-Aufbewahrung (BL-OPS-04)", + "default": "90 Tage, risikoabhängig bis 12 Monate" + }, + "BACKUP_SCHEME": { + "type": "string", + "title": "Backup-Schema (BL-OPS-05)", + "default": "3-2-1 (3 Kopien, 2 Medien, 1 offline/ausgelagert)" + }, + "BACKUP_RETENTION": { + "type": "string", + "title": "Backup-Aufbewahrung (BL-OPS-05)", + "default": "täglich 30 Tage, monatlich 12 Monate" + }, + "BACKUP_TEST_FREQ": { + "type": "string", + "title": "Wiederherstellungstest (BL-OPS-06)", + "default": "jährlich" + }, + "PENTEST_FREQ": { + "type": "string", + "title": "Penetrationstest (BL-OPS-08)", + "default": "jährlich" + }, + "FLAG_INCLUDE_SHOULD": { + "type": "boolean", + "title": "SOLL-Anforderungen einbeziehen (Reifegrad 3 = true)", + "default": true + }, + "FLAG_HIGH_PROTECTION": { + "type": "boolean", + "title": "Zusatzanforderungen HOHER Schutzbedarf einbeziehen", + "default": false + }, + "FLAG_VERY_HIGH_PROTECTION": { + "type": "boolean", + "title": "Zusatzanforderungen SEHR HOHER Schutzbedarf einbeziehen", + "default": false + }, + "FLAG_ELEVATED_PROTECTION": { + "type": "boolean", + "title": "Abgeleitet: HIGH ODER VERY_HIGH aktiv (vom Wizard gesetzt = FLAG_HIGH_PROTECTION || FLAG_VERY_HIGH_PROTECTION)", + "default": false + }, + "FLAG_CLOUD_USED": { + "type": "boolean", + "title": "Cloud-Dienste im Einsatz", + "default": true + }, + "FLAG_AI_USED": { + "type": "boolean", + "title": "KI-/GenAI-Dienste im Einsatz", + "default": true + }, + "FLAG_OT_USED": { + "type": "boolean", + "title": "Produktions-/OT-Umgebung vorhanden", + "default": false + }, + "FLAG_DEV_INHOUSE": { + "type": "boolean", + "title": "Eigene Software-Entwicklung", + "default": false + }, + "FLAG_MOBILE_WORK": { + "type": "boolean", + "title": "Mobiles Arbeiten / Homeoffice zugelassen", + "default": true + }, + "FLAG_MOBILE_DEVICES": { + "type": "boolean", + "title": "Mobile Endgeräte / Datenträger im Einsatz", + "default": true + }, + "FLAG_CRYPTO_PKI": { + "type": "boolean", + "title": "Eigene PKI / Zertifikatsverwaltung", + "default": false + }, + "FLAG_EXTERNAL_IT": { + "type": "boolean", + "title": "Externe IT-Dienstleister genutzt", + "default": true + }, + "FLAG_PERSONAL_DATA": { + "type": "boolean", + "title": "Verarbeitung personenbezogener Daten", + "default": true + }, + "FLAG_CUSTOMER_SYSTEMS": { + "type": "boolean", + "title": "Zugriff auf Kundensysteme (z.B. OEM)", + "default": false + }, + "FLAG_PROTOTYPE_PROTECTION": { + "type": "boolean", + "title": "Prüfziel Prototypenschutz aktiv (Kapitel 8.x)", + "default": false + }, + "FLAG_ISB_INTERNAL": { + "type": "boolean", + "title": "ISB intern besetzt", + "default": true + }, + "FLAG_ISB_EXTERNAL": { + "type": "boolean", + "title": "ISB extern besetzt (externer Dienstleister)", + "default": false + }, + "FLAG_FW_TISAX": { + "type": "boolean", + "title": "Framework: TISAX / VDA ISA anwenden", + "default": true + }, + "FLAG_FW_ISO27001": { + "type": "boolean", + "title": "Framework: ISO/IEC 27001 anwenden", + "default": false + }, + "POLICY_REVIEW_CYCLE": { + "type": "string", + "title": "Prüfzyklus Leitlinie/Richtlinien", + "example": "jährlich", + "default": "jährlich" + }, + "MGMT_REVIEW_CYCLE": { + "type": "string", + "title": "Turnus Managementbewertung", + "example": "jährlich", + "default": "jährlich" + }, + "RISK_REVIEW_CYCLE": { + "type": "string", + "title": "Turnus Risikobeurteilung", + "example": "jährlich", + "default": "jährlich" + }, + "RECORDS_RETENTION": { + "type": "string", + "title": "Aufbewahrung abgelöster Dokumentfassungen", + "example": "3 Jahre", + "default": "3 Jahre" + }, + "AUTHORITY_CONTACTS": { + "type": "string", + "title": "Relevante Behörden/Meldestellen", + "example": "Datenschutz-Aufsichtsbehörde, Polizei (ZAC), BSI/CERT-Bund", + "default": "Datenschutz-Aufsichtsbehörde, Polizei (ZAC), BSI/CERT-Bund" + }, + "THREAT_INTEL_SOURCES": { + "type": "string", + "title": "Quellen für Bedrohungsinformationen", + "example": "CERT-Bund-Warnmeldungen, Herstellerhinweise, CVE-Feeds", + "default": "CERT-Bund-Warnmeldungen, Herstellerhinweise, CVE-Feeds" + }, + "CAPACITY_REVIEW_FREQ": { + "type": "string", + "title": "Turnus Kapazitätsüberwachung", + "example": "monatlich", + "default": "monatlich" + }, + "NTP_SOURCES": { + "type": "string", + "title": "Zugelassene Zeitquellen", + "example": "zwei unabhängige, vertrauenswürdige NTP-Quellen", + "default": "zwei unabhängige, vertrauenswürdige NTP-Quellen" + }, + "DLP_SCOPE": { + "type": "string", + "title": "Abgedeckte Kanäle gegen Datenabfluss", + "example": "E-Mail, Wechseldatenträger, Cloud-Speicher", + "default": "E-Mail, Wechseldatenträger, Cloud-Speicher" + } + }, + "required": [ + "ORG_NAME", + "ISMS_SCOPE", + "ISMS_SCOPE_DESCRIPTION", + "DOC_VERSION", + "DOC_DATE" + ] +} diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md new file mode 100644 index 0000000..6cd5b8d --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-01_Incident-Response-und-Meldeverfahren.md @@ -0,0 +1,71 @@ +# Incident-Response- und Meldeverfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-01) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Meldung, Bewertung, Behandlung und Nachbereitung von Informationssicherheitsvorfällen. Es operationalisiert die zugehörige Richtlinie ({{LINK:R04}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Meldung eines Sicherheitsereignisses (Mitarbeitende, Technik/Monitoring, Externe) über den definierten Meldeweg. + +## 4. Eingaben + +- Meldung/Alarm mit Kurzbeschreibung +- Betroffene Systeme/Informationen (Asset-Inventar) +- Klassifizierung/Schutzbedarf + +## 5. Ablauf + +1. Ereignis melden: Meldung über das {{TOOL_TICKET}} bzw. E-Mail an {{ROLE_ISB}} erfassen. +2. Triage & Klassifizierung: Relevanz, Schweregrad und Kategorie festlegen. +3. Eindämmung: Sofortmaßnahmen zur Begrenzung des Schadens einleiten. +4. Behebung & Wiederherstellung: Ursache beseitigen, Normalbetrieb herstellen. +5. Meldepflichten prüfen: Kunden/OEM, Behörden, bei personenbezogenen Daten {{ROLE_DPO}} (72-Stunden-Frist). +6. Dokumentation & Lessons Learned: Vorfall abschließen, Verbesserungsmaßnahmen ableiten. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Ereignis melden | Meldende Person | {{ROLE_ISB}} | - | - | +| 2 | Triage & Klassifizierung | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Eindämmung | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | +| 4 | Behebung & Wiederherstellung | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 5 | Meldepflichten prüfen | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | {{ROLE_DPO}} | - | +| 6 | Dokumentation & Lessons Learned | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | {{ROLE_MANAGEMENT}} | + +## 7. Ergebnis & Nachweis + +Dokumentierter, abgeschlossener Vorfall im {{TOOL_TICKET}}; abgeleitete Maßnahmen im ISMS-Tool ({{TOOL_NAME}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Zeit bis Ersterfassung (Time-to-Detect/Acknowledge) +- Zeit bis Behebung (Time-to-Resolve) +- Anteil fristgerechter Meldungen + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R04}} +- {{LINK:VA-02}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md new file mode 100644 index 0000000..ad1dbd3 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-02_IT-Notfall-und-Wiederanlaufverfahren.md @@ -0,0 +1,72 @@ +# IT-Notfall- und Wiederanlaufverfahren (BCM) + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-02) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt die Aufrechterhaltung und Wiederherstellung kritischer IT-Dienste bei Ausfall oder Krise. Es operationalisiert die zugehörige Richtlinie ({{LINK:R04}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Ausfall kritischer IT-Dienste, Notfall oder Krisenfall (Eskalation aus VA-01). + +## 4. Eingaben + +- Liste kritischer IT-Dienste mit RTO/RPO +- Wiederanlaufpläne +- Backup-Status (VA-05) + +## 5. Ablauf + +1. Notfall feststellen & einstufen: Ausmaß bewerten, ggf. Krisenstab einberufen. +2. Kommunikation aktivieren: Interne/externe Stakeholder informieren. +3. Wiederanlauf priorisieren: Dienste nach RTO/RPO in Reihenfolge bringen. +4. Wiederherstellung durchführen: Systeme/Daten aus Backup (VA-05) wiederherstellen. +5. Rückkehr zum Normalbetrieb bestätigen & dokumentieren. +6. Nachbereitung & Test-Update: Plan aktualisieren, {{BACKUP_TEST_FREQ}} üben. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Notfall feststellen & einstufen | {{ROLE_IT_LEAD}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 2 | Kommunikation aktivieren | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | - | Mitarbeitende | +| 3 | Wiederanlauf priorisieren | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Wiederherstellung durchführen | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 5 | Rückkehr zum Normalbetrieb bestätigen & | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | {{ROLE_MANAGEMENT}} | +| 6 | Nachbereitung & Test-Update | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Wiederhergestellte Dienste; dokumentierter Notfall/Test im ISMS-Tool ({{TOOL_NAME}}); aktualisierte Wiederanlaufpläne. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Einhaltung RTO/RPO +- Erfolgsquote Wiederherstellungstests +- Aktualität der Notfallpläne + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R04}} +- {{LINK:VA-01}} +- {{LINK:VA-05}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-03_Berechtigungsverfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-03_Berechtigungsverfahren.md new file mode 100644 index 0000000..792beff --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-03_Berechtigungsverfahren.md @@ -0,0 +1,71 @@ +# Berechtigungsverfahren (Joiner/Mover/Leaver und Rezertifizierung) + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-03) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Beantragung, Genehmigung, Änderung, Entzug und regelmäßige Überprüfung von Zugriffsrechten. Es operationalisiert die zugehörige Richtlinie ({{LINK:R08}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Eintritt, Rollenwechsel oder Austritt einer Person; Berechtigungsantrag; fällige Rezertifizierung. + +## 4. Eingaben + +- Personalmeldung (HR) +- Rollen-/Rechtekatalog (RBAC) +- Bestehende Berechtigungen aus dem zentralen Verzeichnis ({{TOOL_IAM}}) + +## 5. Ablauf + +1. Antrag erfassen: Zugang/Recht im {{TOOL_TICKET}} beantragen (Joiner/Mover). +2. Fachliche Genehmigung: Erforderlichkeit nach Minimalprinzip prüfen und freigeben. +3. Umsetzung: Rechte rollenbasiert im zentralen Verzeichnis ({{TOOL_IAM}}) setzen. +4. Leaver/Änderung: Bei Austritt/Wechsel Rechte unverzüglich entziehen/anpassen. +5. Rezertifizierung ({{RECERT_FREQ}}, BL-IAM-05): Owner bestätigen/entziehen Rechte. +6. Privilegierte Konten: gesondert prüfen und protokollieren (BL-IAM-06). + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Antrag erfassen | Vorgesetzte/Fachbereich | {{ROLE_IT_LEAD}} | - | - | +| 2 | Fachliche Genehmigung | Fachbereich/Dateneigentümer | Fachbereich/Dateneigentümer | {{ROLE_ISB}} | - | +| 3 | Umsetzung | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | Antragsteller | +| 4 | Leaver/Änderung | {{ROLE_IT_LEAD}} | {{ROLE_HR_LEAD}} | - | - | +| 5 | Rezertifizierung ({{RECERT_FREQ}}, BL-IAM-05) | Fachbereich/Dateneigentümer | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 6 | Privilegierte Konten | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Dokumentierte Anträge/Genehmigungen im {{TOOL_TICKET}}; aktueller Berechtigungsstand im zentralen Verzeichnis ({{TOOL_IAM}}); Rezertifizierungsnachweis. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil fristgerecht entzogener Leaver-Rechte +- Rezertifizierungsquote +- Zahl verwaister/privilegierter Konten + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R08}} +- {{LINK:VA-01}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md new file mode 100644 index 0000000..db81904 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-04_Change-und-Patch-Management-Verfahren.md @@ -0,0 +1,71 @@ +# Change- und Patch-Management-Verfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-04) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt geplante Änderungen an IT-Systemen sowie das risikoorientierte Einspielen von Patches. Es operationalisiert die zugehörige Richtlinie ({{LINK:R10}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Änderungsbedarf, verfügbarer Patch oder identifizierte Schwachstelle (VA-06). + +## 4. Eingaben + +- Change-/Patch-Antrag +- Risikoeinschätzung +- Patch-SLA (BL-OPS-01) + +## 5. Ablauf + +1. Change beantragen & klassifizieren (Standard/Normal/Notfall) im {{TOOL_TICKET}}. +2. Risiko-/Auswirkungsbewertung inkl. Rollback-Plan. +3. Genehmigung durch CAB/verantwortliche Rolle. +4. Test in getrennter Umgebung (BL-OPS, R10). +5. Umsetzung in Produktion gemäß Patch-SLA (kritisch {{PATCH_SLA_CRIT}}). +6. Verifikation & Dokumentation des Ergebnisses im {{TOOL_TICKET}}. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Change beantragen & klassifizieren (Stan | Antragsteller | {{ROLE_IT_LEAD}} | - | - | +| 2 | Risiko-/Auswirkungsbewertung inkl. Rollb | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 3 | Genehmigung durch CAB/verantwortliche Ro | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Test in getrennter Umgebung (BL-OPS, R10 | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 5 | Umsetzung in Produktion gemäß Patch-SLA | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | Betroffene | +| 6 | Verifikation & Dokumentation des Ergebni | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Dokumentierte, genehmigte und verifizierte Änderung/Patch im {{TOOL_TICKET}}. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Patch-Compliance je Kritikalität +- Anteil erfolgreicher Changes (ohne Rollback) +- Durchlaufzeit kritischer Patches + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R10}} +- {{LINK:VA-06}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-05_Backup-und-Restore-Verfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-05_Backup-und-Restore-Verfahren.md new file mode 100644 index 0000000..a370dc3 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-05_Backup-und-Restore-Verfahren.md @@ -0,0 +1,69 @@ +# Backup- und Restore-Verfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-05) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Datensicherung, Aufbewahrung und Wiederherstellung nach dem {{BACKUP_SCHEME}}-Schema. Es operationalisiert die zugehörige Richtlinie ({{LINK:R10}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Regulärer Sicherungslauf; Wiederherstellungsbedarf; geplanter Restore-Test. + +## 4. Eingaben + +- Sicherungsplan je System +- Klassifizierung/RPO +- Backup-Ziele ({{TECH_BACKUP}}) + +## 5. Ablauf + +1. Sicherung durchführen: automatisierte Backups gemäß {{BACKUP_SCHEME}} (BL-OPS-05). +2. Überwachung: Erfolg/Fehler prüfen, Fehlläufe nachverfolgen ({{TOOL_TICKET}}). +3. Schutz & Auslagerung: 1 Kopie offline/immutable, Aufbewahrung {{BACKUP_RETENTION}}. +4. Restore-Anforderung bearbeiten (bei Bedarf/Notfall, VA-02). +5. Wiederherstellungstest ({{BACKUP_TEST_FREQ}}, BL-OPS-06) durchführen & dokumentieren. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Sicherung durchführen | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Überwachung | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 3 | Schutz & Auslagerung | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 4 | Restore-Anforderung bearbeiten (bei Beda | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | Anforderer | - | +| 5 | Wiederherstellungstest ({{BACKUP_TEST_FREQ}}) | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Protokollierte Sicherungen; dokumentierte Restore-Tests; Nachweis im ISMS-Tool ({{TOOL_NAME}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Backup-Erfolgsquote +- Erfolgsquote Restore-Tests +- Einhaltung RPO + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R10}} +- {{LINK:VA-02}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md new file mode 100644 index 0000000..2f1758c --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-06_Schwachstellenmanagement-Verfahren.md @@ -0,0 +1,69 @@ +# Schwachstellenmanagement-Verfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-06) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Erkennung, Bewertung, Behandlung und technische Prüfung von Schwachstellen. Es operationalisiert die zugehörige Richtlinie ({{LINK:R10}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Regelmäßiger Scan ({{VULN_SCAN_FREQ}}), Sicherheitsmeldung/CVE, Penetrationstest ({{PENTEST_FREQ}}). + +## 4. Eingaben + +- Scan-/Testberichte +- Asset-Inventar & Kritikalität +- Patch-SLA (BL-OPS-01) + +## 5. Ablauf + +1. Identifikation: Schwachstellen-Scan {{VULN_SCAN_FREQ}} (BL-OPS-02) und Meldungen auswerten. +2. Bewertung & Priorisierung nach Kritikalität und Exponierung. +3. Behandlung anstoßen: Patch/Change (VA-04) oder kompensierende Maßnahme. +4. Technische Prüfung: Härtung (BL-OPS-07) und Penetrationstests ({{PENTEST_FREQ}}, BL-OPS-08). +5. Nachverfolgung & Verifikation der Behebung im {{TOOL_TICKET}}. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Identifikation | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Bewertung & Priorisierung nach Kritikali | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 3 | Behandlung anstoßen | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Technische Prüfung | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | Externer Dienstleister | - | +| 5 | Nachverfolgung & Verifikation der Behebu | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Nachverfolgte Schwachstellen mit Behandlungsstatus im {{TOOL_TICKET}}; Testberichte. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Mittlere Behebungszeit je Kritikalität +- Offene kritische Schwachstellen +- Scan-Abdeckung + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R10}} +- {{LINK:VA-04}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md new file mode 100644 index 0000000..92de4f5 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-07_Kryptokonzept-und-Schluesselverwaltung.md @@ -0,0 +1,69 @@ +# Kryptokonzept und Schlüsselverwaltung + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-07) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt den Einsatz kryptografischer Verfahren und die Verwaltung von Schlüsseln über den Lebenszyklus. Es operationalisiert die zugehörige Richtlinie ({{LINK:R09}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Neuer Bedarf an Verschlüsselung/Zertifikaten; Schlüsselerneuerung/-sperrung; Änderung des Stands der Technik. + +## 4. Eingaben + +- Zulässige Algorithmen (BL-CRY-02) +- Schutzbedarf der Daten +- Zertifikats-/Schlüsselbestand + +## 5. Ablauf + +1. Bedarf & Verfahren festlegen: zulässige Algorithmen {{CRYPTO_ALGO}} (BL-CRY-02) wählen. +2. Schlüssel/Zertifikate erzeugen und sicher verteilen (BL-CRY-05). +3. Speicherung & Zugriffsschutz (getrennte Aufbewahrung, {{#if FLAG_CRYPTO_PKI}}PKI, {{/if}}Berechtigungen). +4. Übertragungsschutz sicherstellen: mindestens {{TLS_MIN}} (BL-CRY-01). +5. Erneuerung/Sperrung/Vernichtung dokumentieren. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Bedarf & Verfahren festlegen | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 2 | Schlüssel/Zertifikate erzeugen und siche | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 3 | Speicherung & Zugriffsschutz (getrennte | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 4 | Übertragungsschutz sicherstellen | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 5 | Erneuerung/Sperrung/Vernichtung dokument | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Dokumentiertes Kryptokonzept; nachvollziehbarer Schlüssel-/Zertifikatslebenszyklus. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil konformer Verfahren/Algorithmen +- Ablaufende Zertifikate ohne Erneuerung +- Abdeckung Transportverschlüsselung + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R09}} +- {{LINK:VA-04}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md new file mode 100644 index 0000000..2ca3933 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-08_Asset-und-Klassifizierungsverfahren.md @@ -0,0 +1,69 @@ +# Asset- und Klassifizierungsverfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-08) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Erfassung, Owner-Zuordnung, Klassifizierung und Pflege von Informationswerten und Assets. Es operationalisiert die zugehörige Richtlinie ({{LINK:R02}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Neues/geändertes Asset; Beschaffung; regelmäßige Inventurprüfung. + +## 4. Eingaben + +- Beschaffungs-/Änderungsmeldung +- Klassifizierungsschema +- Asset-Inventar ({{TOOL_NAME}}) + +## 5. Ablauf + +1. Asset erfassen im Inventar ({{TOOL_NAME}}) mit Attributen. +2. Owner zuordnen. +3. Klassifizieren (Vertraulichkeit/Integrität/Verfügbarkeit) durch Owner. +4. Handhabungsvorgaben je Schutzklasse anwenden (Kennzeichnung/Speicherung/Löschung BL-DEL-01). +5. Pflege & Review ({{REVIEW_CYCLE}}) auf Aktualität. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Asset erfassen im Inventar ({{TOOL_NAME}}) | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Owner zuordnen. | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | Asset Owner | +| 3 | Klassifizieren (Vertraulichkeit/Integrit | Asset Owner | Asset Owner | {{ROLE_ISB}} | - | +| 4 | Handhabungsvorgaben je Schutzklasse anwe | Asset Owner | {{ROLE_ISB}} | - | Mitarbeitende | +| 5 | Pflege & Review ({{REVIEW_CYCLE}}) auf A | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Aktuelles, klassifiziertes Asset-Inventar im ISMS-Tool ({{TOOL_NAME}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Inventar-Abdeckung +- Anteil klassifizierter Assets +- Assets ohne Owner + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R02}} +- {{LINK:VA-03}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-09_Risikomanagement-Verfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-09_Risikomanagement-Verfahren.md new file mode 100644 index 0000000..74f7db9 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-09_Risikomanagement-Verfahren.md @@ -0,0 +1,69 @@ +# Risikomanagement-Verfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-09) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Identifikation, Analyse, Bewertung, Behandlung und Überwachung von Informationssicherheitsrisiken. Es operationalisiert die zugehörige Richtlinie ({{LINK:R03}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Neues System/Projekt, Vorfall, Änderung, regelmäßiger Review-Zyklus. + +## 4. Eingaben + +- Asset-/Prozessliste +- Bewertungsskalen & Akzeptanzschwellen +- Bestehendes Risikoregister + +## 5. Ablauf + +1. Risiken identifizieren (Assets, Bedrohungen, Schwachstellen). +2. Analysieren & bewerten (Eintritt × Schadenshöhe) im ISMS-Tool ({{TOOL_NAME}}). +3. Behandlung festlegen (reduzieren/vermeiden/übertragen/akzeptieren) und Maßnahmen planen. +4. Restrisiko-Akzeptanz dokumentieren. +5. Überwachen & aktualisieren ({{REVIEW_CYCLE}} und anlassbezogen). + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Risiken identifizieren (Assets, Bedrohun | {{ROLE_ISB}} | {{ROLE_ISB}} | Asset/Prozessverantwortliche | - | +| 2 | Analysieren & bewerten (Eintritt × Schad | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Behandlung festlegen (reduzieren/vermeid | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | Fachbereich | - | +| 4 | Restrisiko-Akzeptanz dokumentieren. | {{ROLE_MANAGEMENT}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 5 | Überwachen & aktualisieren ({{REVIEW_CYCLE}}) | {{ROLE_ISB}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Gepflegtes Risikoregister mit Behandlungsplan und Akzeptanzentscheidungen im ISMS-Tool ({{TOOL_NAME}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil behandelter Risiken +- Überfällige Maßnahmen +- Aktualität des Risikoregisters + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R03}} +- {{LINK:VA-01}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md new file mode 100644 index 0000000..266d272 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-10_Lieferanten-Onboarding-und-Bewertung.md @@ -0,0 +1,69 @@ +# Lieferanten-Onboarding- und Bewertungsverfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-10) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Auswahl, sicherheitsbezogene Bewertung, vertragliche Bindung und Überwachung von Lieferanten/Dienstleistern. Es operationalisiert die zugehörige Richtlinie ({{LINK:R13}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Neuer Lieferant/Dienstleister mit Zugriff auf Informationen; Vertragsverlängerung; periodische Überprüfung. + +## 4. Eingaben + +- Leistungs-/Schutzbedarfsbeschreibung +- Risikoklassen (BL-SUP-01) +- NDA-/Vertragsvorlagen + +## 5. Ablauf + +1. Bedarf & Risikoklasse bestimmen (Schutzbedarf, Zugriff). +2. Sicherheitsbewertung (Selbstauskunft/Nachweise/TISAX) durchführen. +3. NDA & vertragliche Sicherheitsanforderungen vereinbaren. +4. Verantwortlichkeiten abgrenzen (Betrieb/Sicherheit/Meldung). +5. Ins Lieferantenverzeichnis ({{TOOL_NAME}}) aufnehmen und {{REVIEW_CYCLE}} überprüfen. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Bedarf & Risikoklasse bestimmen (Schutzbedarf, Zugriff) | Einkauf/Fachbereich | {{ROLE_ISB}} | - | - | +| 2 | Sicherheitsbewertung (Selbstauskunft/Nachweise/TISAX) | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereich | - | +| 3 | NDA & vertragliche Sicherheitsanforderun | Einkauf | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 4 | Verantwortlichkeiten abgrenzen (Betrieb/ | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 5 | Ins Lieferantenverzeichnis ({{TOOL_NAME}}) | {{ROLE_ISB}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Bewerteter, vertraglich gebundener Lieferant im Lieferantenverzeichnis ({{TOOL_NAME}}); NDA hinterlegt. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil bewerteter Lieferanten +- NDA-Abdeckung +- Überfällige Lieferantenprüfungen + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R13}} +- {{LINK:VA-11}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md new file mode 100644 index 0000000..5bdbba2 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-11_Cloud-und-KI-Freigabeverfahren.md @@ -0,0 +1,69 @@ +# Cloud- und KI-Freigabeverfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-11) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Bewertung und Freigabe von Cloud- und KI-/GenAI-Diensten sowie die zulässige Nutzung. Es operationalisiert die zugehörige Richtlinie ({{LINK:R12}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Antrag zur Nutzung eines Cloud- oder KI-Dienstes. + +## 4. Eingaben + +- Dienstbeschreibung & Anbieterinfos +- Schutzbedarf/Datenklassen +- Vertrags-/DPA-Unterlagen + +## 5. Ablauf + +1. Antrag erfassen im {{TOOL_TICKET}} (Dienst, Zweck, Datenklassen). +2. Bewertung: Schutzbedarf, Datenlokation/EU, Mandantentrennung, Exit; bei KI Trainings-/Weitergabe-Ausschluss. +3. Vertrag/DPA prüfen (bei KI: Opt-out/Enterprise-Vertrag, EU AI Act). +4. Freigabe & Aufnahme in die Freigabeliste ({{TOOL_NAME}}); zulässige Datenklassen festlegen. +5. Nutzung & Kontrolle: Human-in-the-Loop bei KI, periodische Überprüfung ({{REVIEW_CYCLE}}). + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Antrag erfassen im {{TOOL_TICKET}} (Dien | Antragsteller/Fachbereich | {{ROLE_ISB}} | - | - | +| 2 | Bewertung | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | {{ROLE_DPO}} | +| 3 | Vertrag/DPA prüfen (bei KI | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | {{ROLE_DPO}} | - | +| 4 | Freigabe & Aufnahme in die Freigabeliste | {{ROLE_ISB}} | {{ROLE_ISB}} | - | Fachbereich | +| 5 | Nutzung & Kontrolle | Fachbereich | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Freigabeentscheidung und Freigabeliste im ISMS-Tool ({{TOOL_NAME}}); dokumentierte zulässige Datenklassen. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil freigegebener vs. genutzter Dienste +- Schatten-IT-Funde +- Überfällige Dienst-Reviews + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R12}} +- {{LINK:VA-10}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-12_Awareness-und-Schulungsverfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-12_Awareness-und-Schulungsverfahren.md new file mode 100644 index 0000000..8f25376 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-12_Awareness-und-Schulungsverfahren.md @@ -0,0 +1,69 @@ +# Awareness- und Schulungsverfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-12) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Planung, Durchführung und Nachweis von Sensibilisierung und Schulung zur Informationssicherheit. Es operationalisiert die zugehörige Richtlinie ({{LINK:R05}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Eintritt neuer Mitarbeitender; jährlicher Schulungszyklus; anlassbezogen nach Vorfällen. + +## 4. Eingaben + +- Schulungsplan/Curriculum (BL-HR-01) +- Zielgruppen/Rollen +- Teilnahmestatus ({{TOOL_NAME}}) + +## 5. Ablauf + +1. Schulungsbedarf & Zielgruppen planen (rollenspezifisch). +2. Onboarding-Schulung bei Eintritt durchführen. +3. Regelmäßige Schulung ({{REVIEW_CYCLE}}, BL-HR-01) durchführen. +4. Wirksamkeit prüfen (Phishing-Simulation) und nachschulen. +5. Teilnahme nachweisen im ISMS-Tool ({{TOOL_NAME}}). + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Schulungsbedarf & Zielgruppen planen (ro | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_HR_LEAD}} | - | +| 2 | Onboarding-Schulung bei Eintritt durchfü | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | Mitarbeitende | +| 3 | Regelmäßige Schulung ({{REVIEW_CYCLE}}, | {{ROLE_ISB}} | {{ROLE_ISB}} | - | Mitarbeitende | +| 4 | Wirksamkeit prüfen (Phishing-Simulation) | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 5 | Teilnahme nachweisen im ISMS-Tool ({{TOOL_NAME}}) | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Dokumentierte Schulungsteilnahme und Wirksamkeitsmessung im ISMS-Tool ({{TOOL_NAME}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Schulungsquote +- Phishing-Klickrate +- Anteil rollenspezifischer Schulungen + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R05}} +- {{LINK:VA-01}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md new file mode 100644 index 0000000..7307128 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-13_Logging-und-Monitoring-Verfahren.md @@ -0,0 +1,69 @@ +# Logging- und Monitoring-Verfahren + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-13) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Erhebung, Schutz, Auswertung und Aufbewahrung sicherheitsrelevanter Protokolldaten. Es operationalisiert die zugehörige Richtlinie ({{LINK:R10}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}). + +## 3. Auslöser + +Kontinuierlicher Betrieb; sicherheitsrelevantes Ereignis; Alarm aus {{TECH_SIEM}}. + +## 4. Eingaben + +- Log-Quellen/Systeme +- Aufbewahrungsvorgaben (BL-OPS-04) +- Alarmierungsregeln + +## 5. Ablauf + +1. Log-Quellen anbinden und zentral in {{TECH_SIEM}} erfassen (BL-OPS-04). +2. Manipulationsschutz & Aufbewahrung {{LOG_RETENTION}} sicherstellen. +3. Auswertung & Alarmierung: Regeln pflegen, Auffälligkeiten prüfen. +4. Verdachtsfall an Incident-Response (VA-01) übergeben. +5. Regelmäßige Überprüfung der Abdeckung und Regeln. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Log-Quellen anbinden und zentral in {{TECH_SIEM}} | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 2 | Manipulationsschutz & Aufbewahrung {{LOG_RETENTION}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 3 | Auswertung & Alarmierung | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 4 | Verdachtsfall an Incident-Response (VA-0 | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | +| 5 | Regelmäßige Überprüfung der Abdeckung un | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Zentrale, geschützte Protokollierung mit Auswertung; Nachweis im ISMS-Tool ({{TOOL_NAME}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Log-Quellen-Abdeckung +- Mittlere Zeit bis Alarmreaktion +- Anteil auswertbarer Ereignisse + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R10}} +- {{LINK:VA-01}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md new file mode 100644 index 0000000..6702e7b --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-14_Personalsicherheit-Eignungspruefung.md @@ -0,0 +1,71 @@ +# Personalsicherheit – Eignungsprüfung & sensible Tätigkeiten + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-14) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_HR_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt die Bestimmung sensibler Tätigkeiten, die Eignungs- und Identitätsprüfung bei Einstellung sowie den Umgang mit Verstößen gegen Informationssicherheits- und Vertraulichkeitspflichten. Es operationalisiert die zugehörige Richtlinie ({{LINK:R05}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Einstellungs-, Wechsel- und Austrittsprozesse. + +## 3. Auslöser + +Einstellung, Wechsel in eine sensible Position, Verdacht auf Verstoß, regelmäßiger Review. + +## 4. Eingaben + +- Register sensibler Tätigkeiten ({{LINK:REG-SENS-ROLES}}) +- Stellenbeschreibungen mit Sicherheitsanforderungen +- Personalmeldung (HR); rechtlicher Rahmen (Datenschutz/Mitbestimmung) + +## 5. Ablauf + +1. Sensible Tätigkeitsbereiche/Rollen im **Register sensibler Tätigkeiten ({{LINK:REG-SENS-ROLES}})** bestimmen und die geforderte Prüftiefe je Rolle festlegen. +2. Anforderungen an Positionen in Stellenbeschreibungen hinterlegen und deren Erfüllung sicherstellen. +3. Bei Einstellung die Identität verifizieren; die persönliche Eignung im rechtlich zulässigen Rahmen prüfen (Einstellungsgespräch). +4. Bei sensiblen Rollen erweiterte Prüfungen (Referenzen, Führungszeugnis) im rechtlich zulässigen Rahmen durchführen. +5. Verstöße gegen Informationssicherheits-/Vertraulichkeitspflichten nach dokumentiertem Verfahren behandeln; Nachweis in der Personalakte. +6. Sensible Rollen und Prüftiefe regelmäßig überprüfen ({{REVIEW_CYCLE}}). + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Sensible Tätigkeiten & Prüftiefe bestimmen | {{ROLE_ISB}} | {{ROLE_HR_LEAD}} | Fachbereich | - | +| 2 | Anforderungen in Stellenbeschreibungen | {{ROLE_HR_LEAD}} | {{ROLE_HR_LEAD}} | Fachbereich | - | +| 3 | Identität verifizieren / Eignung prüfen | {{ROLE_HR_LEAD}} | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | +| 4 | Erweiterte Prüfungen (sensible Rollen) | {{ROLE_HR_LEAD}} | {{ROLE_HR_LEAD}} | {{ROLE_ISB}} | - | +| 5 | Umgang mit Verstößen | {{ROLE_HR_LEAD}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 6 | Regelmäßige Überprüfung | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_HR_LEAD}} | - | + +## 7. Ergebnis & Nachweis + +Gepflegtes Register sensibler Tätigkeiten; dokumentierte Eignungs-/Verifizierungsnachweise in der Personalakte; dokumentierte Verstoßfälle. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil sensibler Rollen mit dokumentierter Prüftiefe +- Termingerechte Identitäts-/Eignungsprüfungen +- Offene Verstoßfälle + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R05}} +- Register: {{LINK:REG-SENS-ROLES}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md new file mode 100644 index 0000000..14a28d3 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-15_Interne-Audits-und-Compliancepruefungen.md @@ -0,0 +1,72 @@ +# Interne Audits & Complianceprüfungen + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-15) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Programm, Planung, Durchführung, Berichterstattung und Maßnahmenverfolgung interner Audits sowie die unabhängige Überprüfung des ISMS. Es operationalisiert die zugehörige Richtlinie ({{LINK:R03}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Richtlinien, Verfahren und technischen Anforderungen im Geltungsbereich. + +## 3. Auslöser + +Auditzyklus (BL-GOV-01), wesentliche Änderungen, Anforderung durch die Leitung, Vorbefunde. + +## 4. Eingaben + +- Audit-Programm-Register ({{LINK:REG-AUDIT-PLAN}}) +- Controls / Statement of Applicability (SoA) +- Vorherige Auditberichte & offene Maßnahmen + +## 5. Ablauf + +1. **Audit-Programm** im **Register ({{LINK:REG-AUDIT-PLAN}})** planen (Umfang, geprüfte Controls, Termine, Prüfer) — Turnus gemäß **BL-GOV-01**. +2. Audit **unabhängig** durchführen (Prüfer ≠ Verantwortlicher des geprüften Bereichs). +3. Befunde/Abweichungen erfassen und als Maßnahmen im ISMS-Tool ({{TOOL_NAME}}) anlegen. +4. Auditbericht an {{ROLE_MANAGEMENT}} berichten (Eingabe für die Managementbewertung). +5. Maßnahmen bis zum Abschluss nachverfolgen. +6. Unabhängige Prüfung/Assessment mindestens gemäß **BL-GOV-01** bzw. nach grundlegenden Änderungen. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Audit-Programm planen | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereiche | - | +| 2 | Audit durchführen | Auditor (unabhängig) | {{ROLE_ISB}} | geprüfter Bereich | - | +| 3 | Befunde erfassen / Maßnahmen anlegen | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereich | - | +| 4 | Bericht an Leitung | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | - | {{ROLE_MANAGEMENT}} | +| 5 | Maßnahmen nachverfolgen | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereich | - | +| 6 | Unabhängige Prüfung | externer/unabhängiger Prüfer | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | + +## 7. Ergebnis & Nachweis + +Auditberichte, dokumentierte Befunde/Maßnahmen und ein gepflegtes Audit-Programm ({{LINK:REG-AUDIT-PLAN}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Audit-Abdeckung der Controls +- Offene Findings / Termintreue der Maßnahmen +- Anteil fristgerecht abgeschlossener Audits + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R03}} +- Register: {{LINK:REG-AUDIT-PLAN}} +- Risikomanagement-Verfahren: {{LINK:VA-09}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md new file mode 100644 index 0000000..c560bc6 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-16_Sichere-Beschaffung-Entwicklung-und-Abnahme.md @@ -0,0 +1,72 @@ +# Sichere Beschaffung, Entwicklung & Abnahme + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-16) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren stellt sicher, dass Informationssicherheitsanforderungen fester Bestandteil von Beschaffung, Design, Entwicklung, Erweiterung und Änderung von IT-Diensten und -Systemen sind (Security by Design), inklusive Abnahmetests und Testdatenhandhabung. Es operationalisiert die zugehörige Richtlinie ({{LINK:R11}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für Beschaffung, Eigen-/Fremdentwicklung und Änderung von IT-Diensten/Systemen. + +## 3. Auslöser + +Beschaffung, Neu-/Weiterentwicklung oder wesentliche Änderung eines IT-Dienstes/Systems. + +## 4. Eingaben + +- Sicherheits-/Schutzbedarfsanforderungen; anwendbare ISA-Controls +- Test-/Abnahmekonzept +- Ggf. externe Dienste ({{LINK:REG-EXT-SERVICES}}) + +## 5. Ablauf + +1. Sicherheitsanforderungen spezifizieren (Security by Design) und den Schutzbedarf berücksichtigen. +2. Beschaffung/Änderung anhand der Sicherheitskriterien durchführen.{{#if FLAG_EXTERNAL_IT}} Externe/Cloud-Dienste werden über {{LINK:VA-11}} bewertet und im {{LINK:REG-EXT-SERVICES}} geführt.{{/if}} +3. Abnahmetests unter Sicherheitsaspekten vor der Produktivsetzung; Freigabe im {{TOOL_TICKET}} (Change-Kopplung {{LINK:VA-04}}). +4. Produktivdaten in Tests vermeiden bzw. anonymisieren; Testsysteme angemessen schützen. +5. {{#if FLAG_DEV_INHOUSE}} Für die Eigenentwicklung gelten Secure-Coding-Vorgaben mit Code-Reviews und automatisierten Sicherheitstests (SAST/Dependency-Scan).{{/if}} +6. {{#if FLAG_VERY_HIGH_PROTECTION}} Bei sehr hohem Schutzbedarf erfolgt vor Freigabe eine zusätzliche unabhängige Sicherheitsprüfung/Abnahme.{{/if}} + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Sicherheitsanforderungen spezifizieren | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | Fachbereich | - | +| 2 | Beschaffung/Änderung durchführen | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 3 | Sicherheits-Abnahme / Freigabe | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | Fachbereich | - | +| 4 | Testdaten-Handling | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_DPO}} | - | +| 5 | Secure Coding / Sicherheitstests | Entwicklung | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 6 | Zusätzliche Prüfung (sehr hoher Schutzbedarf) | unabhängiger Prüfer | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | + +## 7. Ergebnis & Nachweis + +Abnahmeprotokolle, Testberichte und Freigaben (im {{TOOL_TICKET}}). Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil Projekte mit dokumentierter Sicherheits-Abnahme +- Kritische Sicherheits-Findings vor Go-Live +- Anteil Tests ohne echte Produktivdaten + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R11}} +- Change-Verfahren: {{LINK:VA-04}} +- Cloud-/KI-Freigabe: {{LINK:VA-11}}; Register: {{LINK:REG-EXT-SERVICES}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-17_Zutritts-und-Besuchermanagement.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-17_Zutritts-und-Besuchermanagement.md new file mode 100644 index 0000000..e017082 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-17_Zutritts-und-Besuchermanagement.md @@ -0,0 +1,67 @@ +# Zutritts- & Besuchermanagement (physisch) + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-17) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_IT_LEAD}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Vergabe und Entzug physischer Zutrittsrechte, das Besuchermanagement sowie den Umgang mit Betriebsmitteln in Sicherheitszonen. Es operationalisiert die zugehörige Richtlinie ({{LINK:R07}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Standorte und Sicherheitszonen. + +## 3. Auslöser + +Eintritt/Austritt/Rollenwechsel, Besuch, Änderung des Zonenkonzepts, regelmäßiger Review. + +## 4. Eingaben + +- Zonen-/Sicherheitskonzept ({{LINK:BASELINE}}, BL-PHY-01/02) +- Personal-/Besuchermeldung +- Bestehende Zutrittsberechtigungen + +## 5. Ablauf + +1. Zutrittsrechte zu Sicherheitszonen werden über das {{TOOL_TICKET}} beantragt, genehmigt und entzogen (Prinzip minimaler Rechte). +2. Besucher werden registriert, ausgewiesen und in schützenswerten Zonen begleitet. +3. Betriebsmittel, Schlüssel und Ausweise werden ausgegeben, zurückgenommen und dokumentiert. +4. Zutrittsberechtigungen werden regelmäßig überprüft ({{REVIEW_CYCLE}}) und bei Austritt/Wechsel unverzüglich angepasst. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Zutrittsrechte vergeben/entziehen | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 2 | Besucher registrieren/begleiten | Empfang/Fachbereich | {{ROLE_IT_LEAD}} | {{ROLE_ISB}} | - | +| 3 | Betriebsmittel/Schlüssel verwalten | {{ROLE_IT_LEAD}} | {{ROLE_IT_LEAD}} | - | - | +| 4 | Zutrittsberechtigungen überprüfen | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | + +## 7. Ergebnis & Nachweis + +Aktuelle Zutrittsberechtigungen und Besucherprotokolle. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Aktualität der Zutrittsliste +- Überfällige Rezertifizierungen von Zutrittsrechten +- Vollständigkeit der Besucherprotokolle + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R07}} +- Berechtigungsverfahren (analog logisch): {{LINK:VA-03}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md new file mode 100644 index 0000000..6ed5e5a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-18_Datenschutz-und-Compliance-Pflege.md @@ -0,0 +1,66 @@ +# Datenschutz- & Compliance-Pflege + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-18) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_DPO}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt die laufende Pflege von Rechts-/Compliance-Register, Verzeichnis der Verarbeitungstätigkeiten (VVT), Löschfristen/Löschkonzept und die Bearbeitung von Betroffenenrechten. Es operationalisiert die zugehörige Richtlinie ({{LINK:R14}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Verarbeitungen personenbezogener Daten sowie rechtliche/vertragliche Anforderungen. + +## 3. Auslöser + +Regelmäßiger Review, neue Rechts-/Vertragsanforderung, Betroffenenanfrage, neue oder geänderte Verarbeitung. + +## 4. Eingaben + +- Rechts-/Compliance-Register (ISMS-Tool, {{TOOL_NAME}}) +- Verzeichnis der Verarbeitungstätigkeiten (VVT) +- Löschkonzept ({{LINK:BASELINE}}, BL-DEL-01) + +## 5. Ablauf + +1. Rechts-/Compliance-Register regelmäßig prüfen und aktualisieren ({{REVIEW_CYCLE}}). +2. Das Verzeichnis der Verarbeitungstätigkeiten (VVT) im ISMS-Tool ({{TOOL_NAME}}) pflegen. +3. Löschfristen und Löschkonzept (BL-DEL-01) umsetzen und überwachen. +4. Betroffenenrechte fristgerecht bearbeiten; Bearbeitung und Ergebnis dokumentieren. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Rechts-/Compliance-Register pflegen | {{ROLE_DPO}} | {{ROLE_ISB}} | Fachbereich | - | +| 2 | VVT pflegen | {{ROLE_DPO}} | {{ROLE_DPO}} | Fachbereich | - | +| 3 | Löschfristen umsetzen/überwachen | {{ROLE_IT_LEAD}} | {{ROLE_DPO}} | {{ROLE_ISB}} | - | +| 4 | Betroffenenrechte bearbeiten | {{ROLE_DPO}} | {{ROLE_DPO}} | {{ROLE_ISB}} | - | + +## 7. Ergebnis & Nachweis + +Aktuelles Rechts-/Compliance-Register und VVT, Löschnachweise, dokumentierte Betroffenenanfragen. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Aktualität des Rechts-/Compliance-Registers +- Fristgerecht bearbeitete Betroffenenanfragen +- Überfällige Löschungen + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R14}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-19_Informationssicherheit-in-Projekten.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-19_Informationssicherheit-in-Projekten.md new file mode 100644 index 0000000..7a53027 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-19_Informationssicherheit-in-Projekten.md @@ -0,0 +1,70 @@ +# Informationssicherheit in Projekten + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-19) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren stellt sicher, dass Informationssicherheit in Projekten von Beginn an berücksichtigt wird: Projektklassifizierung, Risikobewertung in früher Phase und bei Änderungen, Ableitung und Verfolgung von Maßnahmen sowie Einbindung des ISB bei erhöhtem Schutzbedarf. Es operationalisiert die zugehörige Richtlinie ({{LINK:R01}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Projekte mit Bezug zu Informationen, IT-Systemen oder Geschäftsprozessen. + +## 3. Auslöser + +Projektstart, wesentliche Projektänderung, Projektabschluss. + +## 4. Eingaben + +- Kriterienkatalog zur Projekt-Klassifizierung ({{LINK:BASELINE}}, BL-PROJ-01) +- Projektregister ({{LINK:REG-PROJECTS}}) +- Risikobewertungsskala / Risikoregister + +## 5. Ablauf + +1. Projekt zu Beginn anhand des **dokumentierten Kriterienkatalogs (BL-PROJ-01)** hinsichtlich Informationssicherheitsbedarf klassifizieren; Eintrag im **Projektregister ({{LINK:REG-PROJECTS}})**. +2. In einer frühen Projektphase und bei Änderungen eine Risikobewertung durchführen (Kopplung Risikomanagement {{LINK:VA-09}}). +3. Maßnahmen ableiten und als Aufgaben im {{TOOL_TICKET}} nachhalten. +4. {{#if FLAG_ELEVATED_PROTECTION}} Bei erhöhtem Schutzbedarf wird {{ROLE_ISB}} eingebunden; zusätzliche Prüfungen/Freigaben erfolgen vor kritischen Meilensteinen.{{/if}} +5. Vor Projektabschluss die Umsetzung der Maßnahmen prüfen und im Projektregister dokumentieren. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Projekt klassifizieren | Projektleitung | {{ROLE_ISB}} | {{ROLE_ISB}} | - | +| 2 | Risikobewertung durchführen | Projektleitung | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Maßnahmen ableiten & nachhalten | Projektleitung | Projektleitung | {{ROLE_ISB}} | - | +| 4 | ISB-Einbindung (erhöhter Schutzbedarf) | {{ROLE_ISB}} | {{ROLE_ISB}} | Projektleitung | {{ROLE_MANAGEMENT}} | +| 5 | Abschlussprüfung Maßnahmen | Projektleitung | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Gepflegtes Projektregister mit Klassifizierung, Risikobewertung und Maßnahmenstatus. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil klassifizierter Projekte +- Offene Projekt-Sicherheitsmaßnahmen +- Anteil Projekte mit ISB-Einbindung bei erhöhtem Schutzbedarf + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R01}} +- Register: {{LINK:REG-PROJECTS}} +- Risikomanagement-Verfahren: {{LINK:VA-09}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} +- ISA-Mapping-Matrix: {{LINK:ISA_MAPPING}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md new file mode 100644 index 0000000..8c7e201 --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-20_Prototypen-Zutritt-und-Transport.md @@ -0,0 +1,38 @@ +# Prototypen-Zutritt und -Transport + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-20) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_ISB}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren operationalisiert die Richtlinie Prototypenschutz ({{LINK:P01}}). Es regelt Zutritt zu Prototypenbereichen sowie Transport und Lagerung von Prototypen so, dass Vertraulichkeit und Integrität sichergestellt sind. + +## 2. Geltungsbereich + +Das Verfahren gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Personen und Bereiche, die mit Prototypen befasst sind. + +## 3. Ablauf + +### 3.1 Zutritt + +- Zutritt zu Prototypenbereichen nur für namentlich berechtigte Personen; Besucher werden begleitet und protokolliert. +- Zutrittsrechte werden regelmäßig überprüft und bei Bedarf entzogen. + +### 3.2 Transport und Lagerung + +- Transport in abgesicherten, versiegelten Behältnissen mit protokollierter Übergabe. +- Lagerung in gesicherten Zonen mit Zutritts- und Sichtschutz; Ein- und Auslagerung werden nachvollziehbar dokumentiert. + +## 4. Nachweise + +Zutritts-, Übergabe- und Lagerprotokolle werden gemäß Nachweisregister ({{LINK:NACHWEISREGISTER}}) geführt. diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md new file mode 100644 index 0000000..fc6033a --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-21_Nichtkonformitaeten-und-Korrekturmassnahmen.md @@ -0,0 +1,78 @@ +# Nichtkonformitäten & Korrekturmaßnahmen + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-21) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt Erfassung, Ursachenanalyse, Behandlung und Wirksamkeitsbewertung von Nichtkonformitäten sowie die daraus abgeleitete fortlaufende Verbesserung des ISMS. Es operationalisiert die zugehörige Richtlinie ({{LINK:R03}}). + +> Das Verfahren trägt zugleich die Anforderung, Abweichungen zu korrigieren und nachzuverfolgen, wie sie auch die Prüfung der Einhaltung im IS-Betrieb ({{LINK:VA-15}}) verlangt — es gilt daher unabhängig davon, welches Framework der Mandant führt. + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Nichtkonformitäten gegenüber Richtlinien, Verfahren, technischen Vorgaben sowie gesetzlichen und vertraglichen Anforderungen. + +## 3. Auslöser + +Auditbefund, Ergebnis einer Compliance-Prüfung, Sicherheitsvorfall, Abweichung einer Kennzahl vom Zielwert, Hinweis aus dem Betrieb oder von Dritten, Beobachtung in der Managementbewertung. + +## 4. Eingaben + +- Auditberichte und Befunde ({{LINK:VA-15}}) +- Vorfälle und Lessons Learned ({{LINK:VA-01}}) +- Kennzahlen mit Zielwertabweichung ({{LINK:VA-22}}) +- Risikoregister und Risikobehandlungsplan ({{LINK:VA-09}}) + +## 5. Ablauf + +1. **Erfassen:** Nichtkonformität im ISMS-Tool ({{TOOL_NAME}}) mit Herkunft, Beschreibung und betroffenem Bereich anlegen. +2. **Sofort reagieren:** Korrektur zur Beherrschung der Abweichung festlegen und den Umgang mit den Folgen entscheiden. +3. **Ursache analysieren:** Ursache bestimmen und bewerten, ob gleichartige Nichtkonformitäten anderswo bestehen oder auftreten können. +4. **Korrekturmaßnahme festlegen:** Maßnahme mit verantwortlicher Rolle und Termin beschließen; Umfang an der Ursache ausrichten, nicht am Symptom. +5. **Umsetzen und nachverfolgen:** Umsetzung im {{TOOL_NAME}} verfolgen; Verzug eskaliert an {{ROLE_ISB}}. +6. **Wirksamkeit bewerten:** Nach Ablauf des festgelegten Wirksamkeitsintervalls prüfen, ob die Ursache beseitigt ist; erforderlichenfalls Risiken, Maßnahmen und Dokumente anpassen. +7. **Abschließen:** Art der Nichtkonformität, ergriffene Maßnahmen und Ergebnis der Wirksamkeitsbewertung dokumentieren und aufbewahren. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Erfassen | Meldende Person / Auditor | {{ROLE_ISB}} | - | - | +| 2 | Sofort reagieren | Fachbereich | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 3 | Ursache analysieren | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereich | - | +| 4 | Korrekturmaßnahme festlegen | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | Fachbereich | - | +| 5 | Umsetzen und nachverfolgen | Maßnahmenverantwortlicher | {{ROLE_ISB}} | - | {{ROLE_MANAGEMENT}} | +| 6 | Wirksamkeit bewerten | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereich | {{ROLE_MANAGEMENT}} | +| 7 | Abschließen | {{ROLE_ISB}} | {{ROLE_ISB}} | - | - | + +## 7. Ergebnis & Nachweis + +Maßnahmenregister mit Ursachenanalyse, Terminen und dokumentierter Wirksamkeitsbewertung im {{TOOL_NAME}}. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anzahl offener Nichtkonformitäten nach Alter +- Termintreue der Korrekturmaßnahmen +- Anteil der Maßnahmen mit bestätigter Wirksamkeit +- Wiederholungsquote gleichartiger Nichtkonformitäten + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R03}} +- Interne Audits: {{LINK:VA-15}} +- Managementbewertung und Kennzahlen: {{LINK:VA-22}} +- Incident-Response: {{LINK:VA-01}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} + + diff --git a/seed/isms-vorlagenpaket-v2/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md b/seed/isms-vorlagenpaket-v2/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md new file mode 100644 index 0000000..a4fa84f --- /dev/null +++ b/seed/isms-vorlagenpaket-v2/verfahren/VA-22_Managementbewertung-und-Kennzahlen.md @@ -0,0 +1,77 @@ +# Managementbewertung & Kennzahlen + +| Dokumenteninformation | Wert | +|-----------------------|------| +| Dokumententyp | Verfahrensanweisung (VA-22) | +| Geltungsbereich | {{ISMS_SCOPE}} | +| Organisation | {{ORG_NAME}} | +| Prozessverantwortlich | {{ROLE_ISB}} | +| Freigabe durch | {{ROLE_MANAGEMENT}} | +| Version | {{DOC_VERSION}} | +| Datum | {{DOC_DATE}} | +| Status | {{DOC_STATUS}} | + + + +## 1. Zweck + +Dieses Verfahren regelt, wie die Informationssicherheitsleistung gemessen und ausgewertet wird und wie die oberste Leitung das ISMS in geplanten Abständen bewertet. Es operationalisiert die zugehörige Richtlinie ({{LINK:R03}}). + +## 2. Geltungsbereich + +Gilt innerhalb des ISMS-Geltungsbereichs ({{ISMS_SCOPE_DESCRIPTION}}) für alle Kennzahlen der Informationssicherheit und für die Managementbewertung des ISMS. + +## 3. Auslöser + +Messturnus der jeweiligen Kennzahl, Termin der Managementbewertung (BL-GOV-02), wesentliche Änderungen im Geltungsbereich, schwerwiegender Vorfall. + +## 4. Eingaben + +- Kennzahlenblatt mit Zielwerten und Verantwortlichen ({{TOOL_NAME}}) +- Auditergebnisse und offene Befunde ({{LINK:VA-15}}) +- Nichtkonformitäten und Korrekturmaßnahmen ({{LINK:VA-21}}) +- Risikobeurteilung und Status des Risikobehandlungsplans ({{LINK:VA-09}}) +- Vorfälle und Meldepflichten ({{LINK:VA-01}}) +- Rückmeldungen interessierter Parteien + +## 5. Ablauf + +1. **Kennzahlen festlegen:** je Kennzahl bestimmen, was gemessen wird, mit welcher Methode und Datenquelle, in welchem Takt, wer misst, wann ausgewertet wird und wer auswertet. +2. **Messen:** Werte im festgelegten Takt erheben und im {{TOOL_NAME}} erfassen. +3. **Auswerten:** Ergebnisse gegen die Zielwerte bewerten und Trends bilden; eine Abweichung vom Zielwert löst eine Nichtkonformität aus ({{LINK:VA-21}}). +4. **Managementbewertung vorbereiten:** Eingaben zusammenstellen — Status der Maßnahmen aus früheren Bewertungen, Änderungen relevanter interner und externer Themen sowie der Anforderungen interessierter Parteien, Rückmeldungen zur Informationssicherheitsleistung, Rückmeldungen interessierter Parteien, Ergebnisse der Risikobeurteilung, Verbesserungsmöglichkeiten. +5. **Bewertung durchführen:** {{ROLE_MANAGEMENT}} bewertet das ISMS im Turnus {{MGMT_REVIEW_CYCLE}} anhand der festen Tagesordnung (BL-GOV-02). +6. **Beschlüsse fassen:** Entscheidungen zu Verbesserungsmöglichkeiten und zu Änderungsbedarf am ISMS, jeweils mit verantwortlicher Rolle und Termin. +7. **Protokollieren und nachverfolgen:** Protokoll im {{TOOL_NAME}} aufbewahren; Beschlüsse bis zum Abschluss verfolgen. + +## 6. RACI + +| # | Schritt | R (Durchführung) | A (Rechenschaft) | C (Konsultiert) | I (Informiert) | +|---|---------|------------------|------------------|-----------------|----------------| +| 1 | Kennzahlen festlegen | {{ROLE_ISB}} | {{ROLE_MANAGEMENT}} | {{ROLE_IT_LEAD}} | Fachbereiche | +| 2 | Messen | Kennzahlenverantwortlicher | {{ROLE_ISB}} | - | - | +| 3 | Auswerten | {{ROLE_ISB}} | {{ROLE_ISB}} | Fachbereich | - | +| 4 | Bewertung vorbereiten | {{ROLE_ISB}} | {{ROLE_ISB}} | {{ROLE_IT_LEAD}} | - | +| 5 | Bewertung durchführen | {{ROLE_MANAGEMENT}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | Fachbereiche | +| 6 | Beschlüsse fassen | {{ROLE_MANAGEMENT}} | {{ROLE_MANAGEMENT}} | {{ROLE_ISB}} | - | +| 7 | Protokollieren und nachverfolgen | {{ROLE_ISB}} | {{ROLE_ISB}} | - | {{ROLE_MANAGEMENT}} | + +## 7. Ergebnis & Nachweis + +Gepflegtes Kennzahlenblatt mit Messwerten je Periode und ein Protokoll der Managementbewertung mit Beschlüssen, Verantwortlichen und Terminen. Nachweise werden im zentralen Nachweisregister ({{LINK:NACHWEISREGISTER}}) referenziert. + +## 8. Kennzahlen (KPI) + +- Anteil der Kennzahlen, die im Turnus tatsächlich erhoben wurden +- Anteil der Kennzahlen innerhalb des Zielwerts +- Termintreue der Beschlüsse aus der Managementbewertung + +## 9. Verwandte Dokumente + +- Zugehörige Richtlinie: {{LINK:R03}} +- Nichtkonformitäten und Korrekturmaßnahmen: {{LINK:VA-21}} +- Interne Audits: {{LINK:VA-15}} +- Risikomanagement-Verfahren: {{LINK:VA-09}} +- Technische Sicherheits-Baseline: {{LINK:BASELINE}} + + diff --git a/seed/scoping/c1-scope.json b/seed/scoping/c1-scope.json new file mode 100644 index 0000000..be1aa25 --- /dev/null +++ b/seed/scoping/c1-scope.json @@ -0,0 +1,3710 @@ +[ + { + "id": "1.1.1-M1", + "control": "1.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.1.1-M2", + "control": "1.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.1.1-M3", + "control": "1.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.1.1-M4", + "control": "1.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.1.1-M5", + "control": "1.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.1.1-S1", + "control": "1.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.1.1-S2", + "control": "1.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.1.1-S3", + "control": "1.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.1.1-S4", + "control": "1.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.2.1-M1", + "control": "1.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.1-M2", + "control": "1.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.1-M3", + "control": "1.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.1-M4", + "control": "1.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.1-M5", + "control": "1.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.1-M6", + "control": "1.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.2-M1", + "control": "1.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.2-M2", + "control": "1.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.2-M3", + "control": "1.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.2-M4", + "control": "1.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.2-S1", + "control": "1.2.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.2.2-S2", + "control": "1.2.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.2.2-H1", + "control": "1.2.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.2.3-M1", + "control": "1.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.2.3-S1", + "control": "1.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.2.3-S2", + "control": "1.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.2.3-S3", + "control": "1.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.2.3-H1", + "control": "1.2.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.3.1-M1", + "control": "1.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.1-M2", + "control": "1.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.1-S1", + "control": "1.3.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.2-M1", + "control": "1.3.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.2-M2", + "control": "1.3.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.2-M3", + "control": "1.3.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.2-S1", + "control": "1.3.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.3-M1", + "control": "1.3.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.3-M2", + "control": "1.3.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.3-S1", + "control": "1.3.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.3-S2", + "control": "1.3.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.3-S3", + "control": "1.3.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.3-S4", + "control": "1.3.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.4-M1", + "control": "1.3.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.4-M2", + "control": "1.3.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.3.4-S1", + "control": "1.3.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.4-S2", + "control": "1.3.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.4-S3", + "control": "1.3.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.4-S4", + "control": "1.3.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.4-S5", + "control": "1.3.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.3.4-V1", + "control": "1.3.4", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "1.4.1-M1", + "control": "1.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.4.1-M2", + "control": "1.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.4.1-M3", + "control": "1.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.4.1-M4", + "control": "1.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.4.1-S1", + "control": "1.4.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.4.1-S2", + "control": "1.4.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.4.1-S3", + "control": "1.4.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.4.1-S4", + "control": "1.4.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.5.1-M1", + "control": "1.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.1-M2", + "control": "1.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.1-M3", + "control": "1.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.1-M4", + "control": "1.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.1-M5", + "control": "1.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.1-S1", + "control": "1.5.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.5.2-M1", + "control": "1.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.2-M2", + "control": "1.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.5.2-S1", + "control": "1.5.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-M1", + "control": "1.6.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.1-M2", + "control": "1.6.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.1-M3", + "control": "1.6.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.1-S1", + "control": "1.6.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-S2", + "control": "1.6.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-S3", + "control": "1.6.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-S4", + "control": "1.6.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-S5", + "control": "1.6.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-S6", + "control": "1.6.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.1-V1", + "control": "1.6.1", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "1.6.2-M1", + "control": "1.6.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.2-M2", + "control": "1.6.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.2-M3", + "control": "1.6.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.2-S1", + "control": "1.6.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.2-S2", + "control": "1.6.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.2-S3", + "control": "1.6.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.2-H1", + "control": "1.6.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.2-H2", + "control": "1.6.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.2-H3", + "control": "1.6.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.2-H4", + "control": "1.6.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.2-H5", + "control": "1.6.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.2-V1", + "control": "1.6.2", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "1.6.3-M1", + "control": "1.6.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.3-M2", + "control": "1.6.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.3-M3", + "control": "1.6.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "1.6.3-S1", + "control": "1.6.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.3-S2", + "control": "1.6.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.3-S3", + "control": "1.6.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.3-S4", + "control": "1.6.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.3-S5", + "control": "1.6.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.3-S6", + "control": "1.6.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "1.6.3-H1", + "control": "1.6.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.3-H2", + "control": "1.6.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.3-H3", + "control": "1.6.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.3-H4", + "control": "1.6.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.3-H5", + "control": "1.6.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "1.6.3-V1", + "control": "1.6.3", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "2.1.1-M1", + "control": "2.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.1-M2", + "control": "2.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.1-M3", + "control": "2.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.1-S1", + "control": "2.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.1-S2", + "control": "2.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.2-M1", + "control": "2.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.2-M2", + "control": "2.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.2-S1", + "control": "2.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.2-S2", + "control": "2.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.2-S3", + "control": "2.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.3-M1", + "control": "2.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.3-S1", + "control": "2.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.3-S2", + "control": "2.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.3-S3", + "control": "2.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.3-S4", + "control": "2.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.3-S5", + "control": "2.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.3-S6", + "control": "2.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.4-M1", + "control": "2.1.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "2.1.4-S1", + "control": "2.1.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.4-S2", + "control": "2.1.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "2.1.4-H1", + "control": "2.1.4", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "3.1.1-M1", + "control": "3.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "3.1.1-M2", + "control": "3.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "3.1.1-M3", + "control": "3.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "3.1.1-S1", + "control": "3.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "3.1.1-S2", + "control": "3.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "3.1.1-S3", + "control": "3.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "3.1.1-S4", + "control": "3.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "3.1.1-S5", + "control": "3.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "3.1.1-H1", + "control": "3.1.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "3.1.4-M1", + "control": "3.1.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "3.1.4-S1", + "control": "3.1.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "3.1.4-H1", + "control": "3.1.4", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "4.1.1-M1", + "control": "4.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.1-S1", + "control": "4.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.1-H1", + "control": "4.1.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "4.1.2-M1", + "control": "4.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.2-M2", + "control": "4.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.2-S1", + "control": "4.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.2-S2", + "control": "4.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.2-S3", + "control": "4.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.2-H1", + "control": "4.1.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "4.1.2-V1", + "control": "4.1.2", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "4.1.3-M1", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-M2", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-M3", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-M4", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-M5", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-M6", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-M7", + "control": "4.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.1.3-S1", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S10", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S2", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S3", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S4", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S5", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S6", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S7", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S8", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.1.3-S9", + "control": "4.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.2.1-M1", + "control": "4.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.2.1-M2", + "control": "4.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "4.2.1-S1", + "control": "4.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.2.1-S2", + "control": "4.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.2.1-S3", + "control": "4.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.2.1-S4", + "control": "4.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.2.1-S5", + "control": "4.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "4.2.1-H1", + "control": "4.2.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "4.2.1-V1", + "control": "4.2.1", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "4.2.1-V2", + "control": "4.2.1", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.1.1-M1", + "control": "5.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.1.1-S1", + "control": "5.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.1.1-H1", + "control": "5.1.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.1.2-M1", + "control": "5.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.1.2-M2", + "control": "5.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.1.2-M3", + "control": "5.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.1.2-S1", + "control": "5.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.1.2-S2", + "control": "5.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.1.2-S3", + "control": "5.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.1.2-H1", + "control": "5.1.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.1.2-V1", + "control": "5.1.2", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.1-M1", + "control": "5.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.1-S1", + "control": "5.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.1-S2", + "control": "5.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.1-S3", + "control": "5.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.1-S4", + "control": "5.2.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.1-H1", + "control": "5.2.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.2-M1", + "control": "5.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.2-M2", + "control": "5.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.2-S1", + "control": "5.2.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-M1", + "control": "5.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.3-M2", + "control": "5.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.3-S1", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S2", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S3", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S4", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S5", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S6", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S7", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.3-S8", + "control": "5.2.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.4-M1", + "control": "5.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.4-M2", + "control": "5.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.4-M3", + "control": "5.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.4-M4", + "control": "5.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.4-M5", + "control": "5.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.4-S1", + "control": "5.2.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.4-S2", + "control": "5.2.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.4-S3", + "control": "5.2.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.4-H1", + "control": "5.2.4", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.4-H2", + "control": "5.2.4", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.4-V1", + "control": "5.2.4", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.5-M1", + "control": "5.2.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.5-M2", + "control": "5.2.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.5-M3", + "control": "5.2.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.5-S1", + "control": "5.2.5", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.5-S2", + "control": "5.2.5", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.5-S3", + "control": "5.2.5", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.6-M1", + "control": "5.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.6-M2", + "control": "5.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.6-M3", + "control": "5.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.6-M4", + "control": "5.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.6-M5", + "control": "5.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.6-S1", + "control": "5.2.6", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.6-S2", + "control": "5.2.6", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.6-S3", + "control": "5.2.6", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.6-H1", + "control": "5.2.6", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.6-V1", + "control": "5.2.6", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.7-M1", + "control": "5.2.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.7-M2", + "control": "5.2.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.7-S1", + "control": "5.2.7", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.7-S2", + "control": "5.2.7", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.7-H1", + "control": "5.2.7", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-M1", + "control": "5.2.8", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.8-M2", + "control": "5.2.8", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.8-S1", + "control": "5.2.8", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.8-S2", + "control": "5.2.8", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.8-S3", + "control": "5.2.8", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.8-H1", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-H2", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-H3", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-H4", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-H5", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-H6", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-H7", + "control": "5.2.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.8-V1", + "control": "5.2.8", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.8-V2", + "control": "5.2.8", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.8-V3", + "control": "5.2.8", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.9-M1", + "control": "5.2.9", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.9-M2", + "control": "5.2.9", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.2.9-S1", + "control": "5.2.9", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.2.9-H1", + "control": "5.2.9", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.9-H2", + "control": "5.2.9", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.2.9-V1", + "control": "5.2.9", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.9-V2", + "control": "5.2.9", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.2.9-V3", + "control": "5.2.9", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.3.1-M1", + "control": "5.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.1-M2", + "control": "5.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.1-M3", + "control": "5.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.1-M4", + "control": "5.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.1-S1", + "control": "5.3.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.1-S2", + "control": "5.3.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.1-S3", + "control": "5.3.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.1-S4", + "control": "5.3.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.1-S5", + "control": "5.3.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.1-V1", + "control": "5.3.1", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "5.3.2-M1", + "control": "5.3.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.2-S1", + "control": "5.3.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.2-S2", + "control": "5.3.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.2-S3", + "control": "5.3.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.2-H1", + "control": "5.3.2", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "5.3.3-S1", + "control": "5.3.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.4-M1", + "control": "5.3.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.4-S1", + "control": "5.3.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "5.3.4-KI-M1", + "control": "5.3.4-KI", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.4-KI-M2", + "control": "5.3.4-KI", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.4-KI-M3", + "control": "5.3.4-KI", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "5.3.4-KI-S1", + "control": "5.3.4-KI", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.1-M1", + "control": "6.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.1-M2", + "control": "6.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.1-M3", + "control": "6.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.1-S1", + "control": "6.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.1-S2", + "control": "6.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.1-H1", + "control": "6.1.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.1-H2", + "control": "6.1.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.1-H3", + "control": "6.1.1", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.1-V1", + "control": "6.1.1", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "6.1.1-V2", + "control": "6.1.1", + "type": "SEHR HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_VERY_HIGH_PROTECTION" + }, + { + "id": "6.1.2-M1", + "control": "6.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.2-M2", + "control": "6.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.2-M3", + "control": "6.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.2-M4", + "control": "6.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.2-S1", + "control": "6.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.2-S2", + "control": "6.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.2-S3", + "control": "6.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.2-S4", + "control": "6.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.2-S5", + "control": "6.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.3-M1", + "control": "6.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.3-M2", + "control": "6.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.3-M3", + "control": "6.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.3-M4", + "control": "6.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.3-M5", + "control": "6.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "6.1.3-S1", + "control": "6.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.3-S2", + "control": "6.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "6.1.3-H1", + "control": "6.1.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.3-H2", + "control": "6.1.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.3-H3", + "control": "6.1.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.3-H4", + "control": "6.1.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "6.1.3-H5", + "control": "6.1.3", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "7.1.1-M1", + "control": "7.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "7.1.1-M2", + "control": "7.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "7.1.1-S1", + "control": "7.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "7.1.2-M1", + "control": "7.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "7.1.2-M2", + "control": "7.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "7.1.2-M3", + "control": "7.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "informationssicherheit", + "condition": null + }, + { + "id": "8.1.1-M1", + "control": "8.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.1-S1", + "control": "8.1.1", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "8.1.2-M1", + "control": "8.1.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.2-S1", + "control": "8.1.2", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "8.1.3-M1", + "control": "8.1.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.3-S1", + "control": "8.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "8.1.3-S2", + "control": "8.1.3", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "8.1.4-M1", + "control": "8.1.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.4-S1", + "control": "8.1.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "8.1.4-S2", + "control": "8.1.4", + "type": "SOLL", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_INCLUDE_SHOULD" + }, + { + "id": "8.1.4-H1", + "control": "8.1.4", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "8.1.5-M1", + "control": "8.1.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.5-H1", + "control": "8.1.5", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "8.1.6-M1", + "control": "8.1.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.6-M2", + "control": "8.1.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.6-M3", + "control": "8.1.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.7-M1", + "control": "8.1.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.7-M2", + "control": "8.1.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.7-M3", + "control": "8.1.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.7-M4", + "control": "8.1.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.8-M1", + "control": "8.1.8", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.1.8-H1", + "control": "8.1.8", + "type": "HOCH", + "al2": false, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": "FLAG_HIGH_PROTECTION" + }, + { + "id": "8.2.1-M1", + "control": "8.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.1-M2", + "control": "8.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.1-M3", + "control": "8.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.1-M4", + "control": "8.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.2-M1", + "control": "8.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.2-M2", + "control": "8.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.2-M3", + "control": "8.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.2-M4", + "control": "8.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.2-M5", + "control": "8.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.2-M6", + "control": "8.2.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M1", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M2", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M3", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M4", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M5", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M6", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.3-M7", + "control": "8.2.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.4-M1", + "control": "8.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.4-M2", + "control": "8.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.4-M3", + "control": "8.2.4", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.5-M1", + "control": "8.2.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.5-M2", + "control": "8.2.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.5-M3", + "control": "8.2.5", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.6-M1", + "control": "8.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.6-M2", + "control": "8.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.6-M3", + "control": "8.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.6-M4", + "control": "8.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.6-M5", + "control": "8.2.6", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.7-M1", + "control": "8.2.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.2.7-M2", + "control": "8.2.7", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.3.1-M1", + "control": "8.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.3.1-M2", + "control": "8.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.3.1-M3", + "control": "8.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.3.1-M4", + "control": "8.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.3.2-M1", + "control": "8.3.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.1-M1", + "control": "8.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.1-M2", + "control": "8.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.1-M3", + "control": "8.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.2-M1", + "control": "8.4.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.2-M2", + "control": "8.4.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.3-M1", + "control": "8.4.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.3-M2", + "control": "8.4.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.4.3-M3", + "control": "8.4.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.1-M1", + "control": "8.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.1-M2", + "control": "8.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.1-M3", + "control": "8.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.2-M1", + "control": "8.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.2-M2", + "control": "8.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.2-M3", + "control": "8.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "8.5.2-M4", + "control": "8.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "prototypenschutz", + "condition": null + }, + { + "id": "9.1.1-M1", + "control": "9.1.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.2.1-M1", + "control": "9.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.2.1-M2", + "control": "9.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.2.1-M3", + "control": "9.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.2.1-M4", + "control": "9.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.2.1-M5", + "control": "9.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.2.1-M6", + "control": "9.2.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.3.1-M1", + "control": "9.3.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.4.1-M1", + "control": "9.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.4.1-M2", + "control": "9.4.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.5.1-M1", + "control": "9.5.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.5.2-M1", + "control": "9.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.5.2-M2", + "control": "9.5.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.5.3-M1", + "control": "9.5.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.5.3-M2", + "control": "9.5.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.5.3-M3", + "control": "9.5.3", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.6.1-M1", + "control": "9.6.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.6.2-M1", + "control": "9.6.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.6.2-M2", + "control": "9.6.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.6.2-M3", + "control": "9.6.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.7.1-M1", + "control": "9.7.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.7.2-M1", + "control": "9.7.2", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.8.1-M1", + "control": "9.8.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + }, + { + "id": "9.8.1-M2", + "control": "9.8.1", + "type": "MUSS", + "al2": true, + "al3": true, + "pruefziel": "datenschutz", + "condition": null + } +] diff --git a/seed/scoping/c5-controls.json b/seed/scoping/c5-controls.json new file mode 100644 index 0000000..7b50fa0 --- /dev/null +++ b/seed/scoping/c5-controls.json @@ -0,0 +1,564 @@ +[ + { + "control": "1.1.1", + "title": "IS-Leitlinie", + "policy": [ + "L00" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.2.1", + "title": "ISMS/Geltungsbereich", + "policy": [ + "R01" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.2.2", + "title": "Rollen & Verantwortlichkeiten", + "policy": [ + "R01" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.2.3", + "title": "Projektklassifizierung", + "policy": [ + "R01" + ], + "verfahren": [ + "VA-19" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.3.1", + "title": "Identifizierung Informationswerte", + "policy": [ + "R02" + ], + "verfahren": [ + "VA-08" + ], + "needsAsset": true, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.3.2", + "title": "Klassifizierung Informationswerte", + "policy": [ + "R02" + ], + "verfahren": [ + "VA-08" + ], + "needsAsset": true, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.3.3", + "title": "Externe IT-Dienste", + "policy": [ + "R02" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.3.4", + "title": "Software-Freigabe", + "policy": [ + "R02" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.4.1", + "title": "Risikomanagement", + "policy": [ + "R03" + ], + "verfahren": [ + "VA-09" + ], + "needsAsset": false, + "needsRisk": true, + "target": 3 + }, + { + "control": "1.5.1", + "title": "Compliance-/Richtlinienprüfung", + "policy": [ + "R03" + ], + "verfahren": [ + "VA-15" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.5.2", + "title": "Unabhängige Überprüfung", + "policy": [ + "R03" + ], + "verfahren": [ + "VA-15" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.6.1", + "title": "Meldung Sicherheitsereignisse", + "policy": [ + "R04" + ], + "verfahren": [ + "VA-01" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.6.2", + "title": "Behandlung Sicherheitsereignisse", + "policy": [ + "R04" + ], + "verfahren": [ + "VA-01" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "1.6.3", + "title": "Krisen-/Notfallmanagement", + "policy": [ + "R04" + ], + "verfahren": [ + "VA-02" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "2.1.1", + "title": "Personalprüfung (Eignung/Identität)", + "policy": [ + "R05" + ], + "verfahren": [ + "VA-14" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "2.1.2", + "title": "Verpflichtungen (NDA/Richtlinien)", + "policy": [ + "R05" + ], + "verfahren": [ + "VA-14" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "2.1.3", + "title": "Schulung & Sensibilisierung", + "policy": [ + "R05" + ], + "verfahren": [ + "VA-12" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "2.1.4", + "title": "Mobiles Arbeiten", + "policy": [ + "R06" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "3.1.1", + "title": "Sicherheitszonenkonzept", + "policy": [ + "R07" + ], + "verfahren": [ + "VA-17" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "3.1.4", + "title": "Mobile Geräte/Datenträger", + "policy": [ + "R06" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "4.1.1", + "title": "Identifikationsmittel (Lebenszyklus)", + "policy": [ + "R08" + ], + "verfahren": [ + "VA-03" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "4.1.2", + "title": "Benutzerauthentifizierung", + "policy": [ + "R08" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "4.1.3", + "title": "Verwaltung Benutzerkonten", + "policy": [ + "R08" + ], + "verfahren": [ + "VA-03" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "4.2.1", + "title": "Verwaltung Zugriffsrechte", + "policy": [ + "R08" + ], + "verfahren": [ + "VA-03" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.1.1", + "title": "Kryptografie", + "policy": [ + "R09" + ], + "verfahren": [ + "VA-07" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.1.2", + "title": "Netzdienste/sichere Übertragung", + "policy": [ + "R09" + ], + "verfahren": [ + "VA-07" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.1", + "title": "Change-Management", + "policy": [ + "R10" + ], + "verfahren": [ + "VA-04" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.2", + "title": "Trennung Entw./Test/Prod", + "policy": [ + "R10" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.3", + "title": "Schutz vor Schadsoftware", + "policy": [ + "R10" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.4", + "title": "Protokollierung/Logging", + "policy": [ + "R10" + ], + "verfahren": [ + "VA-13" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.5", + "title": "Umgang mit Schwachstellen", + "policy": [ + "R10" + ], + "verfahren": [ + "VA-04", + "VA-06" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.6", + "title": "Prüfung von IT-Systemen (Audit)", + "policy": [ + "R10" + ], + "verfahren": [ + "VA-06" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.7", + "title": "Netzwerkmanagement", + "policy": [ + "R10" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.8", + "title": "Kontinuität IT-Dienste (BCM)", + "policy": [ + "R04" + ], + "verfahren": [ + "VA-02" + ], + "needsAsset": true, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.2.9", + "title": "Backup & Wiederherstellung", + "policy": [ + "R10" + ], + "verfahren": [ + "VA-05" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.3.1", + "title": "Sichere Systementwicklung/Beschaffung", + "policy": [ + "R11" + ], + "verfahren": [ + "VA-16" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.3.2", + "title": "Sicherheit Netzdienste", + "policy": [ + "R11" + ], + "verfahren": [ + "VA-16" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.3.3", + "title": "Beendigung IT-Dienste (nur SOLL)", + "policy": [ + "R11" + ], + "verfahren": [], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.3.4", + "title": "Mandantentrennung (Cloud)", + "policy": [ + "R12" + ], + "verfahren": [ + "VA-11" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "5.3.4-KI", + "title": "KI-/GenAI-Nutzung", + "policy": [ + "R12" + ], + "verfahren": [ + "VA-11" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "6.1.1", + "title": "Lieferantenmanagement", + "policy": [ + "R13" + ], + "verfahren": [ + "VA-10" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "6.1.2", + "title": "Vertraulichkeitsvereinbarungen", + "policy": [ + "R13" + ], + "verfahren": [ + "VA-10" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "6.1.3", + "title": "Geteilte Verantwortlichkeiten (Shared Resp.)", + "policy": [ + "R13" + ], + "verfahren": [ + "VA-10" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "7.1.1", + "title": "Rechtliche/vertragliche Vorgaben", + "policy": [ + "R14" + ], + "verfahren": [ + "VA-18" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + }, + { + "control": "7.1.2", + "title": "Datenschutz-relevante IS-Anforderungen", + "policy": [ + "R14" + ], + "verfahren": [ + "VA-18" + ], + "needsAsset": false, + "needsRisk": false, + "target": 3 + } +] diff --git a/src/app/(app)/account/page.tsx b/src/app/(app)/account/page.tsx new file mode 100644 index 0000000..77f1aea --- /dev/null +++ b/src/app/(app)/account/page.tsx @@ -0,0 +1,123 @@ +import { redirect } from "next/navigation"; +import QRCode from "qrcode"; +import { requireSession } from "@/server/auth"; +import { dbForTenant, prisma } from "@/server/db"; +import { newTotpSecret, totpUri } from "@/server/mfa"; +import { encryptSecret, decryptSecret } from "@/server/secret-crypto"; +import { disableOwnMfa } from "@/server/actions/account"; +import { Button } from "@/components/ui/button"; +import { PageHead, Pill } from "@/components/mockup-ui"; +import { TenantMfaEnrollForm } from "@/components/tenant-mfa-enroll-form"; +import { TenantRecoveryRegenForm } from "@/components/tenant-recovery-regen-form"; +import { PasskeyManager } from "@/components/passkey-manager"; +import { ChangePasswordSelfForm } from "@/components/auth-recovery-forms"; +import { describePasswordPolicy, resolvePasswordPolicy } from "@/lib/password-policy"; + +/** + * Persönliches Konto des Mandanten-Nutzers (Paket C): optionale MFA selbst + * aktivieren/deaktivieren. Login verlangt den Code erst, sobald MFA aktiv ist. + */ +export default async function AccountPage() { + const session = await requireSession(); + const db = dbForTenant(session.user.tenantId); + const user = await db.user.findUnique({ where: { id: session.user.id } }); + if (!user) redirect("/login"); + // Option C (WS4): Passwort/MFA gehören der GLOBALEN Identity. + const identityId = session.user.identityId; + if (!identityId) redirect("/login"); + const identity = await prisma.identity.findUnique({ where: { id: identityId } }); + if (!identity) redirect("/login"); + // SEC2: Passwort-Policy des Mandanten fuer den Hinweistext der Selbstaenderung. + const settings = await db.tenantSettings.findUnique({ where: { tenantId: session.user.tenantId } }); + const policyHint = describePasswordPolicy(resolvePasswordPolicy(settings?.securityPolicy)); + + const enrolled = !!identity.mfaEnrolledAt; + const recoveryLeft = Array.isArray(identity.recoveryCodes) ? identity.recoveryCodes.length : 0; + + // SEC3-b / WS4b: registrierte Passkeys der GLOBALEN Identity (identitätsgebunden). + const passkeys = await prisma.webAuthnCredential.findMany({ + where: { identityId }, + orderBy: { createdAt: "asc" }, + select: { id: true, deviceName: true, createdAt: true }, + }); + const passkeyItems = passkeys.map((p) => ({ id: p.id, deviceName: p.deviceName, createdLabel: p.createdAt.toLocaleDateString("de-DE") })); + + let qr: string | null = null; + let secret: string | null = null; + if (!enrolled) { + secret = identity.mfaSecret ? decryptSecret(identity.mfaSecret) : newTotpSecret(); + if (!identity.mfaSecret) await prisma.identity.update({ where: { id: identityId }, data: { mfaSecret: encryptSecret(secret) } }); + qr = await QRCode.toDataURL(totpUri(identity.email, secret), { margin: 1, width: 192 }); + } + + return ( +
+ + +
+
+
+

Zwei-Faktor-Authentifizierung (optional)

+ {enrolled ? "Aktiv" : "Inaktiv"} +
+ + {enrolled ? ( +
+

MFA ist aktiv. Verbleibende Recovery-Codes: {recoveryLeft}.

+ {/* Re-Authentifizierung (F-08): aktueller TOTP-Code zum Deaktivieren nötig. */} +
+ + +
+ +
+ ) : ( +
+

+ Scannen Sie den QR-Code mit einer Authenticator-App und bestätigen Sie mit dem angezeigten Code. +

+
+ {/* eslint-disable-next-line @next/next/no-img-element */} + QR-Code für die Authenticator-App + {secret} +
+ +
+ )} + +
+

Passkeys (WebAuthn)

+

Alternativer zweiter Faktor: Anmeldung per Gerät (Fingerabdruck/PIN/Sicherheitsschlüssel). Beim Login ist wahlweise TOTP oder Passkey möglich.

+ +
+
+ + {/* SEC2: Passwort selbst aendern — meldet andere Sitzungen ab, behaelt die aktuelle. */} +
+

Passwort ändern

+

+ Nach der Änderung werden alle anderen Sitzungen abgemeldet; diese bleibt bestehen. +

+ +
+ + {/* Option C: Die E-Mail ist der globale Anmeldename der Identity. Ihre + Änderung als Identity-Operation ist bewusst Phase 2 (FEINDESIGN §13). */} +
+

E-Mail-Adresse

+

+ Aktuell: {identity.email}. Die Adresse ist zugleich Ihr globaler Anmeldename. + Eine Änderung ist derzeit nur über die Plattform-Administration möglich. +

+
+
+
+ ); +} diff --git a/src/app/(app)/assets/[id]/edit/page.tsx b/src/app/(app)/assets/[id]/edit/page.tsx new file mode 100644 index 0000000..639c5b6 --- /dev/null +++ b/src/app/(app)/assets/[id]/edit/page.tsx @@ -0,0 +1,11 @@ +import { redirect } from "next/navigation"; + +// Alte Route — Detail/Bearbeiten laufen jetzt als Popup über die Listen-Seite. +export default async function Page({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const { id } = await params; + redirect(`/assets?edit=${id}`); +} diff --git a/src/app/(app)/assets/[id]/page.tsx b/src/app/(app)/assets/[id]/page.tsx new file mode 100644 index 0000000..f4c2e7b --- /dev/null +++ b/src/app/(app)/assets/[id]/page.tsx @@ -0,0 +1,11 @@ +import { redirect } from "next/navigation"; + +// Alte Route — Detail/Bearbeiten laufen jetzt als Popup über die Listen-Seite. +export default async function Page({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const { id } = await params; + redirect(`/assets?detail=${id}`); +} diff --git a/src/app/(app)/assets/layout.tsx b/src/app/(app)/assets/layout.tsx new file mode 100644 index 0000000..683b298 --- /dev/null +++ b/src/app/(app)/assets/layout.tsx @@ -0,0 +1,7 @@ +import { requireModule } from "@/server/modules"; + +/** Serverseitige Modul-Durchsetzung für alle Routen dieses Bereichs (§3.4). */ +export default async function ModuleLayout({ children }: { children: React.ReactNode }) { + await requireModule("assets"); + return <>{children}; +} diff --git a/src/app/(app)/assets/new/page.tsx b/src/app/(app)/assets/new/page.tsx new file mode 100644 index 0000000..6ee04af --- /dev/null +++ b/src/app/(app)/assets/new/page.tsx @@ -0,0 +1,6 @@ +import { redirect } from "next/navigation"; + +// Alte Route — Anlegen läuft jetzt als Popup über die Listen-Seite. +export default function Page() { + redirect("/assets?new=1"); +} diff --git a/src/app/(app)/assets/page.tsx b/src/app/(app)/assets/page.tsx new file mode 100644 index 0000000..479b758 --- /dev/null +++ b/src/app/(app)/assets/page.tsx @@ -0,0 +1,454 @@ +import Link from "next/link"; +import { getTranslations } from "next-intl/server"; +import { Plus, Search } from "lucide-react"; +import type { AssetType } from "@prisma/client"; +import { requireSession } from "@/server/auth"; +import { dbForTenant } from "@/server/db"; +import { hasPermission, requirePermission } from "@/server/rbac"; +import { Button } from "@/components/ui/button"; +import { FilterTabs } from "@/components/filter-tabs"; +import { + CiaBadge, + CiaLegend, + CriticalityPill, + KpiCard, + OwnerChip, + PageHead, + Pill, + Tag, +} from "@/components/mockup-ui"; +import { + AssetCreateModal, + AssetDetailModal, + AssetEditModal, +} from "@/components/asset-modals"; +import { + SupplierDetailModal, + SupplierEditModal, + type SupplierAssetDetail, +} from "@/components/supplier-modals"; +import { + ServiceDetailModal, + ServiceEditModal, + type ServiceAssetDetail, +} from "@/components/service-modals"; +import { + SoftwareDetailModal, + SoftwareEditModal, + type SoftwareAssetDetail, +} from "@/components/software-modals"; +import { + ProjectCreateModal, + ProjectDetailModal, + ProjectEditModal, + type ProjectAssetDetail, +} from "@/components/project-modals"; +import { SUPPLIER_INCLUDE, SERVICE_INCLUDE, SOFTWARE_INCLUDE, PROJECT_INCLUDE } from "@/lib/supplier-include"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +const ASSET_TYPES = ["INFORMATION", "SYSTEM", "APPLICATION", "LOCATION", "SUPPLIER", "IT_SERVICE", "SOFTWARE", "PROJECT", "PERSON", "DATA"] as const; + +const STATUS_TONE = { ACTIVE: "ok", PLANNED: "info", RETIRED: "mut" } as const; + +export default async function AssetsPage({ + searchParams, +}: { + searchParams: Promise<{ q?: string; type?: string; view?: string; detail?: string; edit?: string; new?: string }>; +}) { + const session = await requireSession(); + requirePermission(session, "asset:read"); + const t = await getTranslations("assets"); + const tType = await getTranslations("assetType"); + const tStatus = await getTranslations("assetStatus"); + const tProj = await getTranslations("projects"); + const tSw = await getTranslations("software"); + const tc = await getTranslations("common"); + + const params = await searchParams; + const { q, type } = params; + const activeType = ASSET_TYPES.includes(type as AssetType) ? (type as AssetType) : null; + const db = dbForTenant(session.user.tenantId); + + /* ── Auto-Sicht „Kritische IT-Dienste" (schreibgeschützt, aus Assetinventar/BIA) ── + Ziel des früheren Registers REG-CRIT-SERVICES: keine gepflegte Liste, sondern eine + abgeleitete Sicht. Kritisch = hohe Verfügbarkeit (≥3) ODER stützt einen BIA-kritischen + Prozess. RTO/RPO stammen aus den verknüpften Prozessen (BiaEntry, strengster Wert). */ + if (params.view === "critical") { + const tCrit = await getTranslations("criticality"); + const critical = await db.asset.findMany({ + where: { + type: { in: ["IT_SERVICE", "SYSTEM", "APPLICATION", "SOFTWARE"] }, + OR: [ + { availability: { gte: 3 } }, + { processAssets: { some: { process: { bia: { criticality: { gte: 3 } } } } } }, + ], + }, + include: { + processAssets: { include: { process: { select: { id: true, name: true, bia: { select: { criticality: true, rtoHours: true, rpoHours: true } } } } } }, + relationsFrom: { include: { relatedAsset: { select: { name: true } } } }, + }, + orderBy: [{ availability: "desc" }, { name: "asc" }], + take: 300, + }); + const min = (xs: (number | null | undefined)[]) => { + const v = xs.filter((x): x is number => typeof x === "number"); + return v.length ? Math.min(...v) : null; + }; + const fmtH = (h: number | null) => (h == null ? tc("none") : h >= 24 && h % 24 === 0 ? `${h / 24} d` : `${h} h`); + const rows = critical.map((a) => { + const bias = a.processAssets.map((pa) => pa.process.bia).filter(Boolean); + const biaCrit = Math.max(a.availability, ...bias.map((b) => b!.criticality)); + return { + a, + biaCrit, + rto: min(bias.map((b) => b!.rtoHours)), + rpo: min(bias.map((b) => b!.rpoHours)), + processes: a.processAssets.map((pa) => pa.process.name), + deps: a.relationsFrom.map((r) => r.relatedAsset.name), + }; + }); + + return ( +
+ }>{t("backToInventory")} + } /> +
+ + + + {t("criticalService")} + {t("type")} + {t("biaCriticality")} + RTO + RPO + {t("supportedProcesses")} + {t("dependencies")} + + + + {rows.length === 0 && ( + + {t("criticalEmpty")} + + )} + {rows.map(({ a, biaCrit, rto, rpo, processes, deps }) => ( + + + {a.name} + + {tType(a.type)} + + {fmtH(rto)} + {fmtH(rpo)} + {processes.join(", ") || tc("none")} + {deps.join(", ") || tc("none")} + + ))} + +
+
+

{t("criticalNote")}

+
+ ); + } + + const [assets, allAssets] = await Promise.all([ + db.asset.findMany({ + where: { + ...(q ? { name: { contains: q, mode: "insensitive" } } : {}), + ...(activeType ? { type: activeType } : {}), + }, + include: { + owner: { select: { name: true } }, + supplierProfile: { select: { id: true } }, + serviceProfile: { select: { id: true } }, + relationsFrom: { + include: { relatedAsset: { select: { name: true } } }, + take: 4, + }, + }, + orderBy: { name: "asc" }, + take: 200, + }), + db.asset.findMany({ + select: { type: true, ownerId: true, confidentiality: true, integrity: true, availability: true }, + }), + ]); + + const total = allAssets.length; + const typeCount = new Set(allAssets.map((a) => a.type)).size; + const highProtection = allAssets.filter( + (a) => Math.max(a.confidentiality, a.integrity, a.availability) >= 3 + ).length; + const withoutOwner = allAssets.filter((a) => !a.ownerId).length; + const suppliers = allAssets.filter((a) => a.type === "SUPPLIER").length; + + const canWrite = hasPermission(session, "asset:write"); + + // Popup-Zustand aus searchParams: ?detail= (read-only), ?edit=, ?new=1 + const modalId = params.edit && canWrite ? params.edit : params.detail; + const isEdit = Boolean(params.edit && canWrite); + + // Art des Popups vorab bestimmen: Lieferanten & IT-Services mit Fachprofil + // werden direkt hier als Fach-Cockpit gerendert (backHref="/assets"), sodass + // man auf der Asset-Seite bleibt; profillose Alt-Assets bleiben normale Assets. + const modalMeta = modalId + ? await db.asset.findUnique({ + where: { id: modalId }, + select: { + type: true, + supplierProfile: { select: { id: true } }, + serviceProfile: { select: { id: true } }, + softwareProfile: { select: { id: true } }, + projectProfile: { select: { id: true } }, + }, + }) + : null; + const modalKind: "supplier" | "service" | "software" | "project" | "asset" | null = !modalMeta + ? null + : modalMeta.type === "SUPPLIER" && modalMeta.supplierProfile + ? "supplier" + : modalMeta.type === "IT_SERVICE" && modalMeta.serviceProfile + ? "service" + : modalMeta.type === "SOFTWARE" && modalMeta.softwareProfile + ? "software" + : modalMeta.type === "PROJECT" && modalMeta.projectProfile + ? "project" + : "asset"; + + const supplierModal = + modalKind === "supplier" + ? ((await db.asset.findUnique({ where: { id: modalId! }, include: SUPPLIER_INCLUDE })) as SupplierAssetDetail | null) + : null; + const serviceModal = + modalKind === "service" + ? ((await db.asset.findUnique({ where: { id: modalId! }, include: SERVICE_INCLUDE })) as ServiceAssetDetail | null) + : null; + const softwareModal = + modalKind === "software" + ? ((await db.asset.findUnique({ where: { id: modalId! }, include: SOFTWARE_INCLUDE })) as SoftwareAssetDetail | null) + : null; + const projectModal = + modalKind === "project" + ? ((await db.asset.findUnique({ where: { id: modalId! }, include: PROJECT_INCLUDE })) as ProjectAssetDetail | null) + : null; + const providers = + (modalKind === "service" || modalKind === "software") && isEdit + ? await db.asset.findMany({ + where: { type: "SUPPLIER", supplierProfile: { isNot: null } }, + select: { id: true, name: true }, + orderBy: { name: "asc" }, + }) + : []; + + const modalAsset = + modalKind === "asset" + ? await db.asset.findUnique({ + where: { id: modalId! }, + include: { + owner: { select: { name: true } }, + relationsFrom: { + include: { + relatedAsset: { + select: { + id: true, + name: true, + type: true, + confidentiality: true, + integrity: true, + availability: true, + }, + }, + }, + }, + relationsTo: { include: { asset: { select: { id: true, name: true } } } }, + processAssets: { include: { process: { select: { id: true, name: true } } } }, + riskAssets: { + include: { risk: { select: { id: true, refNo: true, title: true, score: true } } }, + orderBy: { risk: { score: "desc" } }, + }, + }, + }) + : null; + + const users = + canWrite && (params.edit || params.new) + ? await db.user.findMany({ + where: { status: "ACTIVE" }, + select: { id: true, name: true }, + orderBy: { name: "asc" }, + }) + : []; + const otherAssets = + canWrite && params.edit && modalAsset + ? await db.asset.findMany({ + where: { id: { not: modalAsset.id } }, + select: { id: true, name: true }, + orderBy: { name: "asc" }, + }) + : []; + + const typeHref = (v: string | null) => + `/assets${v ? `?type=${v}` : ""}${q ? `${v ? "&" : "?"}q=${encodeURIComponent(q)}` : ""}`; + + return ( +
+ + + + {canWrite && ( + activeType === "PROJECT" ? ( + + ) : activeType === "SOFTWARE" ? ( + + ) : ( + + ) + )} + + } + /> + + +
+ + + 0 ? t("kpiNoOwnerTrend") : undefined} + trendColor="warn" + /> + +
+ +
+
+ ({ + href: typeHref(v), + label: tType(v), + active: activeType === v, + })), + ]} + /> +
+ {activeType && } + + + +
+ + + + Asset + {t("type")} + {t("owner")} + + + {t("protection")} + + + + {t("dependencies")} + {t("status")} + + + + {assets.length === 0 && ( + + + {t("empty")} + + + )} + {assets.map((asset) => ( + + + + {asset.name} + + + + {tType(asset.type)} + + + + + + + + + {asset.relationsFrom.length + ? asset.relationsFrom.map((r) => r.relatedAsset.name).join(", ") + : tc("none")} + + + {tStatus(asset.status)} + + + ))} + +
+
+ + {/* Lieferanten- & IT-Service-Cockpits werden hier direkt gerendert + (backHref="/assets"), damit man auf der Asset-Seite bleibt. */} + {supplierModal && isEdit ? ( + + ) : supplierModal ? ( + + ) : serviceModal && isEdit ? ( + + ) : serviceModal ? ( + + ) : softwareModal && isEdit ? ( + + ) : softwareModal ? ( + + ) : projectModal && isEdit ? ( + + ) : projectModal ? ( + + ) : params.new && canWrite && activeType === "PROJECT" ? ( + + ) : modalAsset && isEdit ? ( + + ) : modalAsset ? ( + + ) : params.new && canWrite ? ( + + ) : null} +
+ ); +} diff --git a/src/app/(app)/audit-readiness/[auditId]/controls/page.tsx b/src/app/(app)/audit-readiness/[auditId]/controls/page.tsx new file mode 100644 index 0000000..572170a --- /dev/null +++ b/src/app/(app)/audit-readiness/[auditId]/controls/page.tsx @@ -0,0 +1,217 @@ +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { Sparkles, FileText, AlertTriangle } from "lucide-react"; +import { requireSession } from "@/server/auth"; +import { dbForTenant } from "@/server/db"; +import { hasPermission } from "@/server/rbac"; +import { PageHead, Pill } from "@/components/mockup-ui"; +import { Button } from "@/components/ui/button"; +import { Textarea } from "@/components/ui/textarea"; +import { Input } from "@/components/ui/input"; +import { buildControlGroups, type ControlGroup, type ControlLamp, type RequirementBullet } from "@/server/control-descriptions-context"; +import { isAiConfigured } from "@/server/ai/client"; +import { draftControlDescription, draftControl, confirmDescription, saveDescription, saveOpenAnswer } from "@/server/actions/control-descriptions"; + +const LAMP_TONE: Record = { green: "ok", amber: "warn", red: "risk" }; +const LAMP_LABEL: Record = { green: "vollständig", amber: "in Arbeit", red: "offen" }; +const CONF_TONE: Record = { high: "ok", medium: "warn", low: "mut" }; +const CONF_LABEL: Record = { high: "hohe Konfidenz", medium: "mittlere Konfidenz", low: "niedrige Konfidenz" }; +const STATUS_TONE: Record = { open: "mut", draft: "info", confirmed: "ok" }; +const STATUS_LABEL: Record = { open: "manuell zu erfassen", draft: "Entwurf", confirmed: "übernommen" }; + +/** + * Control-Beschreibungen (VDA-ISA-Spalte 4) — Seite des Audit-Wizards. + * Links das Control-Verzeichnis mit Status-Ampel, rechts je Control die + * Kontrollfrage, die Anforderungs-Bullets (aus PolicyRequirement) und je Bullet + * ein KI-Entwurf-Kasten (Text, Quelle, Konfidenz, Aktionen Übernehmen/Anpassen/ + * Neu). Ohne Beleg: „kein Beleg gefunden" + gezielte Rückfrage (openAnswer). + * Die Wizard-Shell/Navigation liefert V5A; hier nur diese Seite. + */ +export default async function ControlsPage({ params, searchParams }: { params: Promise<{ auditId: string }>; searchParams: Promise<{ control?: string }> }) { + const session = await requireSession(); + const { auditId } = await params; + const db = dbForTenant(session.user.tenantId); + + const audit = await db.audit.findFirst({ where: { id: auditId } }); + if (!audit) notFound(); + + const canUse = hasPermission(session, "onboarding:use"); + const aiOn = isAiConfigured(); + const groups = await buildControlGroups(db); + + const sp = await searchParams; + const selected: ControlGroup | undefined = groups.find((g) => g.control === sp.control) ?? groups[0]; + + return ( +
+ }> + ABGABE-Vorschau + + } + /> + + {!aiOn && ( +
+ + KI-Entwurf ist nicht konfiguriert (kein ANTHROPIC_API_KEY). Beschreibungen können manuell erfasst werden; die übrige Funktion steht bereit. +
+ )} + + {groups.length === 0 ? ( +

Keine Anforderungen vorhanden — zunächst das Richtlinienpaket importieren.

+ ) : ( +
+ {/* Control-Verzeichnis mit Status-Ampel */} +
    + {groups.map((g) => { + const isCurrent = selected?.control === g.control; + return ( +
  1. + + + {g.control} · {g.frage} + +
  2. + ); + })} +
+ + {/* Detail des gewählten Controls */} + {selected && ( +
+
+
+

{selected.control} · {selected.frage}

+

{selected.bullets.length} Anforderung(en) · {selected.evidence.length} Nachweis(e)

+
+
+ {LAMP_LABEL[selected.lamp]} + {canUse && aiOn && ( +
+ +
+ )} +
+
+ +
+ {selected.bullets.map((b) => ( + + ))} +
+ + {!canUse &&

Nur Lesezugriff.

} +
+ )} +
+ )} +
+ ); +} + +function BulletCard({ bullet, canUse, aiOn }: { bullet: RequirementBullet; canUse: boolean; aiOn: boolean }) { + const d = bullet.description; + const status = d?.status ?? "open"; + return ( +
+
+ {bullet.obligation} + {bullet.reqId} + {STATUS_LABEL[status]} +
+

{bullet.requirement}

+ {bullet.implementation &&

Umsetzungshinweis: {bullet.implementation}

} + {bullet.documents.length > 0 && ( +
+ {bullet.documents.map((doc) => ( + {doc.code} · v{doc.version} + ))} +
+ )} + + {/* KI-Entwurf-Kasten */} +
+ {d?.draftText ? ( + <> +
+ Beschreibung der Umsetzung + {d.confidence && {CONF_LABEL[d.confidence] ?? d.confidence}} +
+

{d.draftText}

+ {d.sourceRef &&

Quelle: {d.sourceRef}

} + {canUse && ( +
+ {status !== "confirmed" && ( +
+ +
+ )} + + {aiOn && ( +
+ +
+ )} +
+ )} + + ) : bullet.hasEvidence ? ( +
+ Noch kein Entwurf. {aiOn ? "KI-Entwurf aus verknüpften Belegen erzeugen." : "Manuell erfassen."} + {canUse && aiOn && ( +
+ +
+ )} + {canUse && } +
+ ) : ( + <> +

+ Kein Beleg gefunden. Bitte gezielte Rückfrage beantworten: +

+ {canUse ? ( +
+