7aabfbe5b5
Geteilte Schicht für alle Surfaces (Workspace-Anwälte, Cyber-Risiko-Projekt,
Admin): ein Mandant markiert ein Control als "nicht anwendbar" → in seinen
Use-Case-Ansichten (und künftig Repo-Scans) ausgeblendet.
- Migration 156: compliance.control_suppressions (PK tenant_id+control_uuid),
reversibel (active + reverted_*), auditierbar (actor/reason/created_at).
[migration-approved]
- Service control_suppression: suppress/revert/list_suppressions +
suppressed_control_uuids (geteilter Filter).
- Routes: GET/POST /v1/controls/suppressions + POST .../{uuid}/revert (X-Tenant-ID).
- controls_for_use_case: optionaler X-Tenant-ID + include_suppressed; suppressed
per Default versteckt (nie gelöscht), suppressed_count, suppressed-Flag pro
Control. Agenten/CRA ohne Tenant unberührt.
- Tests: Request-Validierung + import-safety (E2E-Zyklus gegen macmini bewiesen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
36 lines
1.4 KiB
SQL
36 lines
1.4 KiB
SQL
-- Migration 156: control_suppressions — per-tenant Applicability-Override.
|
|
-- Ein Mandant markiert ein Control als "unbrauchbar / nicht anwendbar" -> es
|
|
-- wird in seinen Use-Case-Ansichten (und künftig Repo-Scans) ausgeblendet.
|
|
-- REVERSIBEL (active=false + reverted_*, Zeile bleibt) und AUDIT-tauglich
|
|
-- (actor + reason + created_at beantworten "warum nicht geprüft?"). PER-TENANT.
|
|
-- Composite PK (tenant_id, control_uuid) = genau eine aktuelle Zeile je
|
|
-- Mandant+Control; Re-Suppress reaktiviert. Additiv, idempotent. [migration-approved]
|
|
|
|
SET search_path TO compliance, public;
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables
|
|
WHERE table_schema = 'compliance'
|
|
AND table_name = 'canonical_controls') THEN
|
|
|
|
CREATE TABLE IF NOT EXISTS control_suppressions (
|
|
tenant_id UUID NOT NULL,
|
|
control_uuid UUID NOT NULL
|
|
REFERENCES canonical_controls(id) ON DELETE CASCADE,
|
|
reason TEXT,
|
|
actor VARCHAR(120),
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
reverted_at TIMESTAMPTZ,
|
|
reverted_by VARCHAR(120),
|
|
revert_reason TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (tenant_id, control_uuid)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_ctrl_suppr_tenant_active
|
|
ON control_suppressions(tenant_id, active);
|
|
|
|
END IF;
|
|
END $$;
|