Basis: Certvia dev@a48c5fb als Fundament für Craftvia
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 $$;
|
||||
Reference in New Issue
Block a user