197 lines
5.2 KiB
PL/PgSQL
197 lines
5.2 KiB
PL/PgSQL
-- ===============================
|
|
-- ComplyCore Supabase IAM + RLS Init
|
|
-- Includes:
|
|
-- - Tenants
|
|
-- - Users
|
|
-- - Service Accounts (NPEs)
|
|
-- - Audit Logs
|
|
-- ===============================
|
|
|
|
-- 1. Define user roles
|
|
CREATE TYPE user_role AS ENUM ('client_user', 'client_admin', 'reviewer', 'superadmin');
|
|
|
|
-- 2. Define authentication scopes for service accounts
|
|
CREATE TYPE api_scope AS ENUM ('upload', 'evaluate', 'read_reports', 'manage_projects');
|
|
|
|
-- 3. Tenants table
|
|
CREATE TABLE tenants (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
dba_name TEXT,
|
|
cage_code TEXT,
|
|
sam_uid TEXT,
|
|
duns_number TEXT,
|
|
naics_codes TEXT[],
|
|
address_line1 TEXT,
|
|
address_line2 TEXT,
|
|
city TEXT,
|
|
state_province TEXT,
|
|
postal_code TEXT,
|
|
country TEXT DEFAULT 'USA',
|
|
primary_contact_name TEXT,
|
|
primary_contact_email TEXT,
|
|
primary_contact_phone TEXT,
|
|
cmmc_target_level TEXT DEFAULT 'Level 2',
|
|
sponsoring_agency TEXT,
|
|
compliance_status TEXT DEFAULT 'pending',
|
|
notes TEXT,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
|
|
);
|
|
|
|
-- 4. Users table (linked to auth.users)
|
|
CREATE TABLE users (
|
|
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
|
role user_role NOT NULL DEFAULT 'client_user',
|
|
|
|
-- Identity
|
|
first_name TEXT NOT NULL,
|
|
last_name TEXT NOT NULL,
|
|
job_title TEXT,
|
|
department TEXT,
|
|
|
|
-- Contact
|
|
email TEXT NOT NULL UNIQUE,
|
|
phone_office TEXT,
|
|
phone_mobile TEXT,
|
|
address_line1 TEXT,
|
|
address_line2 TEXT,
|
|
city TEXT,
|
|
state_province TEXT,
|
|
postal_code TEXT,
|
|
country TEXT DEFAULT 'USA',
|
|
|
|
-- Flags
|
|
is_service_account BOOLEAN DEFAULT false,
|
|
mfa_enabled BOOLEAN DEFAULT false,
|
|
|
|
-- System
|
|
last_login_at TIMESTAMP WITH TIME ZONE,
|
|
notes TEXT,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
|
|
);
|
|
|
|
-- 5. Service Accounts (API Clients)
|
|
CREATE TABLE api_clients (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
|
name TEXT NOT NULL,
|
|
client_id TEXT NOT NULL UNIQUE,
|
|
client_secret TEXT NOT NULL,
|
|
scopes api_scope[] NOT NULL,
|
|
enabled BOOLEAN DEFAULT true,
|
|
created_by UUID REFERENCES users(id),
|
|
description TEXT,
|
|
last_used_at TIMESTAMP WITH TIME ZONE,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
|
|
);
|
|
|
|
-- 6. Evaluation results table
|
|
CREATE TABLE evaluations (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
|
project_id UUID NOT NULL,
|
|
control_id TEXT NOT NULL,
|
|
status TEXT CHECK (status IN ('implemented', 'partial', 'missing')),
|
|
notes TEXT,
|
|
created_by UUID REFERENCES users(id),
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
|
|
);
|
|
|
|
-- 7. Audit log
|
|
CREATE TABLE auth_audit_log (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
actor_id UUID, -- user or service account
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
|
action TEXT NOT NULL,
|
|
target_table TEXT,
|
|
target_id UUID,
|
|
ip_address TEXT,
|
|
user_agent TEXT,
|
|
result TEXT CHECK (result IN ('success', 'fail')) DEFAULT 'success',
|
|
timestamp TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
|
|
);
|
|
|
|
-- =======================================
|
|
-- Session Context Claims
|
|
-- =======================================
|
|
|
|
CREATE OR REPLACE FUNCTION set_claim_context()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
AS $$
|
|
DECLARE
|
|
v_role TEXT;
|
|
v_tenant UUID;
|
|
BEGIN
|
|
SELECT role, tenant_id INTO v_role, v_tenant
|
|
FROM public.users
|
|
WHERE id = auth.uid();
|
|
|
|
-- Set session-scoped variables
|
|
PERFORM set_config('request.jwt.claim.role', v_role, true);
|
|
PERFORM set_config('request.jwt.claim.tenant_id', v_tenant::text, true);
|
|
END;
|
|
$$;
|
|
|
|
-- =======================================
|
|
-- Row-Level Security (RLS) Policies
|
|
-- =======================================
|
|
|
|
-- Enable RLS
|
|
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE evaluations ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE api_clients ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE auth_audit_log ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Users: only see own row
|
|
CREATE POLICY "Self-access only"
|
|
ON users
|
|
USING (id = auth.uid());
|
|
|
|
-- Evaluations: Tenant isolation for client roles
|
|
CREATE POLICY "Tenant isolation"
|
|
ON evaluations
|
|
FOR ALL
|
|
USING (
|
|
(current_setting('request.jwt.claim.role', true) IN ('client_user', 'client_admin'))
|
|
AND tenant_id = current_setting('request.jwt.claim.tenant_id', true)::uuid
|
|
);
|
|
|
|
-- Evaluations: Reviewer read-only access
|
|
CREATE POLICY "Reviewer read access"
|
|
ON evaluations
|
|
FOR SELECT
|
|
USING (
|
|
current_setting('request.jwt.claim.role', true) = 'reviewer'
|
|
);
|
|
|
|
-- Evaluations: Superadmin full access
|
|
CREATE POLICY "Superadmin full access"
|
|
ON evaluations
|
|
FOR ALL
|
|
USING (
|
|
current_setting('request.jwt.claim.role', true) = 'superadmin'
|
|
)
|
|
WITH CHECK (
|
|
current_setting('request.jwt.claim.role', true) = 'superadmin'
|
|
);
|
|
|
|
-- Service Accounts: Restrict to own tenant + enabled
|
|
CREATE POLICY "API client isolation"
|
|
ON api_clients
|
|
FOR ALL
|
|
USING (
|
|
tenant_id = current_setting('request.jwt.claim.tenant_id', true)::uuid
|
|
AND enabled = true
|
|
);
|
|
|
|
-- Audit Log: tenant-scoped visibility
|
|
CREATE POLICY "Audit tenant visibility"
|
|
ON auth_audit_log
|
|
FOR SELECT
|
|
USING (
|
|
tenant_id = current_setting('request.jwt.claim.tenant_id', true)::uuid
|
|
);
|