krona-staff/migrations/0002_security_hardening.up.sql

68 lines
4.9 KiB
SQL

ALTER TABLE staff_outbox ADD COLUMN IF NOT EXISTS subject_type TEXT;
ALTER TABLE staff_outbox ADD COLUMN IF NOT EXISTS subject_id VARCHAR(26);
ALTER TABLE staff_outbox ADD COLUMN IF NOT EXISTS actor_type TEXT;
ALTER TABLE staff_outbox ADD COLUMN IF NOT EXISTS actor_id VARCHAR(26);
UPDATE staff_outbox
SET subject_type = COALESCE(subject_type, payload #>> '{subject,type}', 'staff.Unknown'),
subject_id = COALESCE(subject_id, payload #>> '{subject,id}', id),
actor_type = COALESCE(actor_type, payload #>> '{actor,type}', 'service'),
actor_id = COALESCE(actor_id, payload #>> '{actor,id}', correlation_id)
WHERE subject_type IS NULL OR subject_id IS NULL OR actor_type IS NULL OR actor_id IS NULL;
ALTER TABLE staff_outbox ALTER COLUMN subject_type SET NOT NULL;
ALTER TABLE staff_outbox ALTER COLUMN subject_id SET NOT NULL;
ALTER TABLE staff_outbox ALTER COLUMN actor_type SET NOT NULL;
ALTER TABLE staff_outbox ALTER COLUMN actor_id SET NOT NULL;
ALTER TABLE staff_outbox DROP CONSTRAINT IF EXISTS staff_outbox_subject_id_check;
ALTER TABLE staff_outbox ADD CONSTRAINT staff_outbox_subject_id_check CHECK (subject_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_outbox DROP CONSTRAINT IF EXISTS staff_outbox_actor_type_check;
ALTER TABLE staff_outbox ADD CONSTRAINT staff_outbox_actor_type_check CHECK (actor_type IN ('user', 'service'));
ALTER TABLE staff_outbox DROP CONSTRAINT IF EXISTS staff_outbox_actor_id_check;
ALTER TABLE staff_outbox ADD CONSTRAINT staff_outbox_actor_id_check CHECK (actor_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_outbox DROP CONSTRAINT IF EXISTS staff_outbox_correlation_id_check;
ALTER TABLE staff_outbox ADD CONSTRAINT staff_outbox_correlation_id_check CHECK (correlation_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_outbox DROP CONSTRAINT IF EXISTS staff_outbox_causation_id_check;
ALTER TABLE staff_outbox ADD CONSTRAINT staff_outbox_causation_id_check CHECK (causation_id IS NULL OR causation_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_inbox DROP CONSTRAINT IF EXISTS staff_inbox_event_id_check;
ALTER TABLE staff_inbox ADD CONSTRAINT staff_inbox_event_id_check CHECK (event_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_inbox DROP CONSTRAINT IF EXISTS staff_inbox_tenant_id_check;
ALTER TABLE staff_inbox ADD CONSTRAINT staff_inbox_tenant_id_check CHECK (tenant_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_inbox DROP CONSTRAINT IF EXISTS staff_inbox_correlation_id_check;
ALTER TABLE staff_inbox ADD CONSTRAINT staff_inbox_correlation_id_check CHECK (correlation_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_inbox DROP CONSTRAINT IF EXISTS staff_inbox_causation_id_check;
ALTER TABLE staff_inbox ADD CONSTRAINT staff_inbox_causation_id_check CHECK (causation_id IS NULL OR causation_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_idempotency_keys DROP CONSTRAINT IF EXISTS staff_idempotency_keys_tenant_id_check;
ALTER TABLE staff_idempotency_keys ADD CONSTRAINT staff_idempotency_keys_tenant_id_check CHECK (tenant_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_audit_log DROP CONSTRAINT IF EXISTS staff_audit_log_id_check;
ALTER TABLE staff_audit_log ADD CONSTRAINT staff_audit_log_id_check CHECK (id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_audit_log DROP CONSTRAINT IF EXISTS staff_audit_log_tenant_id_check;
ALTER TABLE staff_audit_log ADD CONSTRAINT staff_audit_log_tenant_id_check CHECK (tenant_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_audit_log DROP CONSTRAINT IF EXISTS staff_audit_log_actor_id_check;
ALTER TABLE staff_audit_log ADD CONSTRAINT staff_audit_log_actor_id_check CHECK (actor_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_audit_log DROP CONSTRAINT IF EXISTS staff_audit_log_entity_id_check;
ALTER TABLE staff_audit_log ADD CONSTRAINT staff_audit_log_entity_id_check CHECK (entity_id IS NULL OR entity_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
ALTER TABLE staff_audit_log DROP CONSTRAINT IF EXISTS staff_audit_log_correlation_id_check;
ALTER TABLE staff_audit_log ADD CONSTRAINT staff_audit_log_correlation_id_check CHECK (correlation_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$');
DROP POLICY IF EXISTS staff_audit_tenant_isolation ON staff_audit_log;
DROP POLICY IF EXISTS staff_audit_tenant_select ON staff_audit_log;
DROP POLICY IF EXISTS staff_audit_tenant_insert ON staff_audit_log;
CREATE POLICY staff_audit_tenant_select ON staff_audit_log FOR SELECT USING (tenant_id = current_setting('app.tenant_id', true));
CREATE POLICY staff_audit_tenant_insert ON staff_audit_log FOR INSERT WITH CHECK (
tenant_id = current_setting('app.tenant_id', true)
AND actor_id = current_setting('app.user_id', true)
);
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'krona_staff_app') THEN
GRANT USAGE ON SCHEMA public TO krona_staff_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON staff_outbox, staff_inbox, staff_idempotency_keys TO krona_staff_app;
GRANT SELECT, INSERT ON staff_audit_log TO krona_staff_app;
REVOKE UPDATE, DELETE, TRUNCATE ON staff_audit_log FROM krona_staff_app;
END IF;
END
$$;