chore(rls): stage projects canary path
This commit is contained in:
19
scripts/ops/awooop-rls-canary-wave1-2-projects-rollback.sql
Normal file
19
scripts/ops/awooop-rls-canary-wave1-2-projects-rollback.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Rollback for AwoooP RLS Canary Wave 1.2.
|
||||
-- This removes project table policies and disables RLS on awooop_projects.
|
||||
-- It intentionally keeps awooop_operator_list_projects() so deployed API code
|
||||
-- that uses the operator list path remains compatible.
|
||||
|
||||
BEGIN;
|
||||
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL statement_timeout = '30s';
|
||||
|
||||
DROP POLICY IF EXISTS awooop_projects_select_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS awooop_projects_insert_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS awooop_projects_update_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS awooop_projects_delete_tenant ON awooop_projects;
|
||||
|
||||
ALTER TABLE awooop_projects NO FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE awooop_projects DISABLE ROW LEVEL SECURITY;
|
||||
|
||||
COMMIT;
|
||||
107
scripts/ops/awooop-rls-canary-wave1-2-projects.sql
Normal file
107
scripts/ops/awooop-rls-canary-wave1-2-projects.sql
Normal file
@@ -0,0 +1,107 @@
|
||||
-- AwoooP RLS Canary Wave 1.2: projects table with explicit operator list path
|
||||
-- Date: 2026-05-12
|
||||
--
|
||||
-- Scope:
|
||||
-- - awooop_projects
|
||||
--
|
||||
-- Safety model:
|
||||
-- - normal app access is tenant-scoped by app.project_id.
|
||||
-- - Operator Console cross-tenant list uses a fixed SECURITY DEFINER
|
||||
-- function owned by the migration/operator role.
|
||||
-- - no NULL/empty-string/__platform__ policy bypass.
|
||||
|
||||
BEGIN;
|
||||
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL statement_timeout = '30s';
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
total_rows bigint;
|
||||
null_project_rows bigint;
|
||||
BEGIN
|
||||
IF to_regclass('public.awooop_projects') IS NULL THEN
|
||||
RAISE EXCEPTION 'RLS canary target table does not exist: awooop_projects';
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'awooop_projects'
|
||||
AND column_name = 'project_id'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'RLS canary target missing project_id: awooop_projects';
|
||||
END IF;
|
||||
|
||||
SELECT COUNT(*), COUNT(*) FILTER (WHERE project_id IS NULL)
|
||||
INTO total_rows, null_project_rows
|
||||
FROM awooop_projects;
|
||||
|
||||
IF null_project_rows <> 0 THEN
|
||||
RAISE EXCEPTION 'RLS canary target has NULL project_id rows: %, nulls=%',
|
||||
'awooop_projects', null_project_rows;
|
||||
END IF;
|
||||
|
||||
IF total_rows > 20 THEN
|
||||
RAISE EXCEPTION 'RLS canary wave1.2 reviewed cap exceeded: %, rows=%',
|
||||
'awooop_projects', total_rows;
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.awooop_operator_list_projects()
|
||||
RETURNS TABLE (
|
||||
project_id varchar,
|
||||
display_name varchar,
|
||||
migration_mode varchar,
|
||||
budget_limit_usd numeric,
|
||||
is_active boolean,
|
||||
created_at timestamp without time zone
|
||||
)
|
||||
LANGUAGE sql
|
||||
STABLE
|
||||
SECURITY DEFINER
|
||||
SET search_path = public, pg_catalog
|
||||
AS $$
|
||||
SELECT
|
||||
p.project_id,
|
||||
p.display_name,
|
||||
p.migration_mode,
|
||||
p.budget_limit_usd,
|
||||
p.is_active,
|
||||
p.created_at
|
||||
FROM public.awooop_projects AS p
|
||||
ORDER BY p.created_at ASC;
|
||||
$$;
|
||||
|
||||
REVOKE ALL ON FUNCTION public.awooop_operator_list_projects() FROM PUBLIC;
|
||||
GRANT EXECUTE ON FUNCTION public.awooop_operator_list_projects() TO awooop_app;
|
||||
|
||||
ALTER TABLE awooop_projects ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE awooop_projects FORCE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS awooop_projects_select_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS awooop_projects_insert_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS awooop_projects_update_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS awooop_projects_delete_tenant ON awooop_projects;
|
||||
DROP POLICY IF EXISTS projects_tenant_isolation ON awooop_projects;
|
||||
|
||||
CREATE POLICY awooop_projects_select_tenant ON awooop_projects
|
||||
FOR SELECT TO awooop_app
|
||||
USING (project_id = current_setting('app.project_id', TRUE));
|
||||
|
||||
CREATE POLICY awooop_projects_insert_tenant ON awooop_projects
|
||||
FOR INSERT TO awooop_app
|
||||
WITH CHECK (project_id = current_setting('app.project_id', TRUE));
|
||||
|
||||
CREATE POLICY awooop_projects_update_tenant ON awooop_projects
|
||||
FOR UPDATE TO awooop_app
|
||||
USING (project_id = current_setting('app.project_id', TRUE))
|
||||
WITH CHECK (project_id = current_setting('app.project_id', TRUE));
|
||||
|
||||
CREATE POLICY awooop_projects_delete_tenant ON awooop_projects
|
||||
FOR DELETE TO awooop_app
|
||||
USING (project_id = current_setting('app.project_id', TRUE));
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user