0050_project_storage_grants.sql 1.6 KB

12345678910111213141516171819202122232425262728293031
  1. -- 0050_project_storage_grants — M5 S3 sprint (cross-project storage sharing).
  2. --
  3. -- A GRANTER project explicitly shares one file (by file id) OR a whole path
  4. -- prefix with a GRANTEE project. The grantee can then mint a download URL for
  5. -- exactly the granted resource — nothing else. This is the ONLY sanctioned
  6. -- exception to strict cross-project storage isolation.
  7. --
  8. -- Strict-deny by construction: access is allowed ONLY when a matching row
  9. -- exists with revoked_at IS NULL. Revoke sets revoked_at (never deletes) so the
  10. -- row can be re-activated on a fresh grant and the unique index stays intact.
  11. -- Lands on the control DB (Postgres). Additive + idempotent.
  12. CREATE TABLE IF NOT EXISTS "project_storage_grants" (
  13. "id" text PRIMARY KEY NOT NULL,
  14. "granter_project_id" text NOT NULL,
  15. "grantee_project_id" text NOT NULL,
  16. "resource" text NOT NULL,
  17. "is_prefix" boolean DEFAULT false NOT NULL,
  18. "created_by" text,
  19. "created_at" timestamp with time zone DEFAULT now() NOT NULL,
  20. "revoked_at" timestamp with time zone
  21. );
  22. --> statement-breakpoint
  23. DO $$ BEGIN
  24. ALTER TABLE "project_storage_grants" ADD CONSTRAINT "project_storage_grants_granter_project_id_projects_id_fk" FOREIGN KEY ("granter_project_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;
  25. EXCEPTION
  26. WHEN duplicate_object THEN null;
  27. END $$;
  28. --> statement-breakpoint
  29. CREATE UNIQUE INDEX IF NOT EXISTS "project_storage_grants_unique_idx" ON "project_storage_grants" ("granter_project_id","grantee_project_id","resource");
  30. --> statement-breakpoint
  31. CREATE INDEX IF NOT EXISTS "project_storage_grants_grantee_idx" ON "project_storage_grants" ("grantee_project_id");