64 lines
3.8 KiB
SQL
64 lines
3.8 KiB
SQL
|
|
-- ════════════════════════════════════════════════════════════════════════════
|
||
|
|
-- Cleanup #3: drop storage.access_grants (and everything attached to it)
|
||
|
|
-- ════════════════════════════════════════════════════════════════════════════
|
||
|
|
-- The final step of the role-keyed ReBAC cleanup. By the time this migration
|
||
|
|
-- runs:
|
||
|
|
--
|
||
|
|
-- * Every read path goes through `storage.role_grants` (cleanup #1 / #2).
|
||
|
|
-- * The engine no longer has a `grant()` method; `set_role()` /
|
||
|
|
-- `clear_role()` are the only writes.
|
||
|
|
-- * The HTTP surface (`POST /api/grants`, `PUT /api/grants/role`) only
|
||
|
|
-- accepts role-keyed shapes.
|
||
|
|
-- * `share_service`, `subject_group_service`, `auth_application_service`,
|
||
|
|
-- `share_pg_repository`, and `integration_test_support` all read
|
||
|
|
-- `role_grants` exclusively.
|
||
|
|
-- * `storage.role_grants` has its own cascade triggers
|
||
|
|
-- (`trg_cleanup_role_grants_*`) and reverse-cascade
|
||
|
|
-- (`trg_cleanup_share_on_role_grant_delete`), added in cleanup #2.
|
||
|
|
--
|
||
|
|
-- So `access_grants` is fully unreferenced — we can drop it together with
|
||
|
|
-- the helper triggers + functions defined in
|
||
|
|
-- `20260520000000_rebac_access_grants.sql` and
|
||
|
|
-- `20260612000001_share_grant_reverse_cascade.sql`.
|
||
|
|
--
|
||
|
|
-- Roll-back posture: this is destructive. There is no down migration. The
|
||
|
|
-- D-Prep backfill is one-way (role-keyed rows are derived from
|
||
|
|
-- permission-keyed clusters; the reverse reconstruction would need a fixed
|
||
|
|
-- bundle mapping that may have shifted between releases). Recovering
|
||
|
|
-- requires restoring from a backup taken before this migration runs.
|
||
|
|
|
||
|
|
-- ── 1. Drop the access_grants triggers FROM their source tables ────────────
|
||
|
|
-- These triggers live on storage.folders / storage.files / auth.users /
|
||
|
|
-- storage.shares. Dropping access_grants doesn't implicitly remove them
|
||
|
|
-- (the trigger row points at the source table; the body references the
|
||
|
|
-- target table, and that body is what breaks once access_grants is gone).
|
||
|
|
-- Drop them explicitly so subsequent DELETEs on those source tables don't
|
||
|
|
-- error out.
|
||
|
|
|
||
|
|
DROP TRIGGER IF EXISTS trg_cleanup_grants_folder ON storage.folders;
|
||
|
|
DROP TRIGGER IF EXISTS trg_cleanup_grants_file ON storage.files;
|
||
|
|
DROP TRIGGER IF EXISTS trg_cleanup_grants_user ON auth.users;
|
||
|
|
DROP TRIGGER IF EXISTS trg_cleanup_grants_token ON storage.shares;
|
||
|
|
|
||
|
|
-- The reverse-cascade trigger is ON access_grants and goes away with the
|
||
|
|
-- table — but the IF EXISTS makes this safe regardless of drop order.
|
||
|
|
DROP TRIGGER IF EXISTS trg_cleanup_share_on_grant_delete ON storage.access_grants;
|
||
|
|
|
||
|
|
|
||
|
|
-- ── 2. Drop the trigger helper functions ────────────────────────────────────
|
||
|
|
-- No other code references these — the `cleanup_role_grants_*` equivalents
|
||
|
|
-- defined in cleanup #2 carry the same behaviour against role_grants.
|
||
|
|
|
||
|
|
DROP FUNCTION IF EXISTS storage.cleanup_grants_on_resource_delete();
|
||
|
|
DROP FUNCTION IF EXISTS storage.cleanup_grants_on_subject_delete();
|
||
|
|
DROP FUNCTION IF EXISTS storage.cleanup_share_on_last_token_grant_delete();
|
||
|
|
|
||
|
|
|
||
|
|
-- ── 3. Drop the table ──────────────────────────────────────────────────────
|
||
|
|
-- CASCADE removes any remaining dependent objects (indexes, comments, and
|
||
|
|
-- the reverse-cascade trigger if it survived step 1). With every Rust code
|
||
|
|
-- path already routed through role_grants, nothing in the application
|
||
|
|
-- layer will notice.
|
||
|
|
|
||
|
|
DROP TABLE IF EXISTS storage.access_grants CASCADE;
|