accounts/sql/20260204_rbac_root_constraints.sql

71 lines
2.6 KiB
SQL

-- Idempotent RBAC/root migration for existing deployments.
-- Apply with a privileged DB user before restarting account service in production.
CREATE TABLE IF NOT EXISTS public.rbac_roles (
role_key TEXT PRIMARY KEY,
description TEXT NOT NULL DEFAULT '',
priority INTEGER NOT NULL DEFAULT 100,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS public.rbac_permissions (
permission_key TEXT PRIMARY KEY,
description TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS public.rbac_role_permissions (
role_key TEXT NOT NULL REFERENCES public.rbac_roles(role_key) ON DELETE CASCADE,
permission_key TEXT NOT NULL REFERENCES public.rbac_permissions(permission_key) ON DELETE CASCADE,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (role_key, permission_key)
);
CREATE UNIQUE INDEX IF NOT EXISTS users_single_root_role_uk
ON public.users ((lower(role)))
WHERE lower(role) = 'root';
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'users_root_email_ck'
) THEN
ALTER TABLE public.users
ADD CONSTRAINT users_root_email_ck
CHECK (lower(role) <> 'root' OR lower(email) = 'admin@svc.plus');
END IF;
END
$$;
INSERT INTO public.rbac_roles (role_key, description, priority) VALUES
('root', 'single root account', 0),
('operator', 'operation role with configurable permissions', 10),
('user', 'standard subscription user', 20),
('readonly', 'read-only experience account', 30)
ON CONFLICT (role_key) DO NOTHING;
INSERT INTO public.rbac_permissions (permission_key, description) VALUES
('admin.settings.read', 'read admin matrix settings'),
('admin.settings.write', 'update admin matrix settings'),
('admin.users.metrics.read', 'read user metrics'),
('admin.agents.status.read', 'read agent status'),
('admin.users.pause.write', 'pause users'),
('admin.users.resume.write', 'resume users'),
('admin.users.delete.write', 'delete users'),
('admin.users.renew_uuid.write', 'renew user proxy uuid'),
('admin.users.role.write', 'update/reset user role'),
('admin.blacklist.read', 'read blacklist'),
('admin.blacklist.write', 'update blacklist')
ON CONFLICT (permission_key) DO NOTHING;
INSERT INTO public.rbac_role_permissions (role_key, permission_key, enabled)
SELECT 'operator', permission_key, true
FROM public.rbac_permissions
ON CONFLICT (role_key, permission_key) DO NOTHING;