Skip to content

fix: add storage RLS policies for 360ghar-storage bucket#17

Open
RaviSahu1520 wants to merge 1 commit into
mainfrom
fix/storage-rls-policies
Open

fix: add storage RLS policies for 360ghar-storage bucket#17
RaviSahu1520 wants to merge 1 commit into
mainfrom
fix/storage-rls-policies

Conversation

@RaviSahu1520
Copy link
Copy Markdown
Collaborator

@RaviSahu1520 RaviSahu1520 commented May 19, 2026

Problem

Flutter uploads listing/profile/chat photos directly to Supabase Storage but no RLS policies existed on storage.objects, causing:

Storage upload failed: new row violates row-level security policy

This blocked all image uploads from the mobile app (listing photos, profile photos, chat photos).

Root Cause

  • The bucket 360ghar-storage is private with RLS enabled on storage.objects
  • The original bucket config migration (20260115000100) noted that RLS policies must be created manually via the Supabase Dashboard but this was never done
  • A draft migration existed but was untracked, only covered listings/, and was never applied

Fix

Adds comprehensive RLS policies for the 360ghar-storage bucket:

Policy Operation Who Path Pattern
users_insert_own INSERT authenticated users/{uid}/*
users_select_own SELECT authenticated users/{uid}/*
users_update_own UPDATE authenticated users/{uid}/*
users_delete_own DELETE authenticated users/{uid}/*
authenticated_read_listings SELECT authenticated users/*/listings/*
public_read_agent_avatars SELECT anon + authenticated agents/*/avatars/*
authenticated_read_tours SELECT authenticated users/*/tours/*

Covers all Flutter upload paths: listings/, profile/, chats/.

Post-Merge Action Required

This migration must be run via the Supabase Dashboard SQL Editor (standard migrations lack owner permissions on storage.objects).

  1. Go to Supabase Dashboard → SQL Editor
  2. Copy the contents of supabase/migrations/20260516000000_configure_storage_rls_policies.sql
  3. Paste and click Run

Uploads will start working immediately after the policies are applied.

Files Changed

  • supabase/migrations/20260516000000_configure_storage_rls_policies.sql (new file, 115 lines)

Summary by cubic

Add RLS policies for 360ghar-storage to fix “new row violates row-level security policy” and restore listing, profile, and chat image uploads from Flutter.

  • Bug Fixes

    • Enabled RLS on storage.objects and added INSERT/SELECT/UPDATE/DELETE for users/{uid}/*.
    • Authenticated SELECT for users/*/listings/* and users/*/tours/*; public SELECT for agents/*/avatars/*.
    • Covers Flutter paths: users/{uid}/listings/*, users/{uid}/profile/*, users/{uid}/chats/*; removed old narrow policies.
  • Migration

    • Run supabase/migrations/20260516000000_configure_storage_rls_policies.sql in the Supabase Dashboard SQL Editor (needed for storage.objects permissions).
    • Uploads will work immediately after applying.

Written for commit 7630275. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features
    • Implemented secure file storage with granular user-based access controls
    • Enabled authenticated users to manage and share listing photos
    • Made agent profile avatars publicly visible
    • Implemented restricted access controls for tour content
    • Migrated and consolidated storage security policies

Review Change Stack

Greptile Summary

This PR adds a new SQL migration (20260516000000_configure_storage_rls_policies.sql) that creates seven RLS policies on storage.objects for the 360ghar-storage Supabase bucket, unblocking Flutter direct uploads of listing, profile, and chat photos. It must be applied manually via the Supabase Dashboard SQL Editor rather than the standard migration pipeline.

  • Own-folder CRUD policies grant INSERT/SELECT/UPDATE/DELETE to authenticated users for paths matching users/{uid}/<subfolder>/<file> (exactly one subfolder deep).
  • Cross-user SELECT policies allow any authenticated user to read listings/ and tours/ paths, and allow public (anon) access to agents/*/avatars/*.
  • Chat photos have no cross-user SELECT policy; recipients cannot directly read or create signed URLs for users/{sender_uid}/chats/* files from the Flutter client.

Confidence Score: 3/5

Safe to merge as SQL, but the missing chat cross-user SELECT policy means chat photo recipients may hit access denials if Flutter fetches those objects directly or calls createSignedUrl client-side.

The own-folder CRUD policies and cross-user listing/tour/avatar reads are well-constructed with tight regex depth. The gap is that users//chats/ has no SELECT policy for non-owners, leaving a real risk of silent breakage for the chat photo feature this PR is meant to fix.

supabase/migrations/20260516000000_configure_storage_rls_policies.sql — specifically the absence of a cross-user SELECT for the chats path and the 10-year signed URL expiry note.

Security Review

  • Long-lived signed URLs (10-year expiry): The migration comment references signed URLs with a 10-year expiry. URLs of this duration are functionally permanent public links; leakage via logs, forwarded messages, or API responses would expose private storage objects indefinitely.
  • Chat photo visibility gap: No SELECT policy exists for users/*/chats/* paths, so chat recipients cannot directly fetch or sign those objects from the client — a present access-control gap if Flutter ever calls createSignedUrl client-side for received chat photos.

Important Files Changed

Filename Overview
supabase/migrations/20260516000000_configure_storage_rls_policies.sql Adds RLS policies for 360ghar-storage; covers INSERT/SELECT/UPDATE/DELETE for own-folder paths and cross-user reads for listings, tours, and agent avatars, but lacks a SELECT policy for chat photos, which would block recipients from reading received images if they fetch directly or create signed URLs client-side.

Reviews (1): Last reviewed commit: "fix: add storage RLS policies for 360gha..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Flutter uploads directly to Supabase Storage (listings, profile, chats)
but no RLS policies existed on storage.objects, causing:
  'new row violates row-level security policy'

Adds policies:
- users_insert_own (INSERT for authenticated users into own folder)
- users_select_own (SELECT own files)
- users_update_own (UPDATE own files)
- users_delete_own (DELETE own files)
- authenticated_read_listings (cross-user read for listing photos)
- public_read_agent_avatars (public read for agent avatars)
- authenticated_read_tours (authenticated read for tour content)

Covers all Flutter upload paths: users/{uid}/listings/*, profile/*, chats/*

Run via Supabase Dashboard SQL Editor (migrations lack owner perms
on storage.objects).
@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This PR introduces a Supabase Storage migration that enables row-level security and defines seven access policies for the 360ghar-storage bucket. Authenticated users gain full CRUD control over their own user-folder paths, cross-user read access for listing photos, and tour content. Public anonymous access is granted for agent avatar images. Legacy policies are conditionally removed.

Changes

Storage RLS Configuration

Layer / File(s) Summary
Storage RLS policies for 360ghar-storage bucket
supabase/migrations/20260516000000_configure_storage_rls_policies.sql
RLS enabled on storage.objects. Seven policies govern authenticated user CRUD on own users/{auth.uid()}/... paths, cross-user authenticated reads of listing photos, public reads of agent avatars, and authenticated reads of tour content. Legacy flatmates_listing_photos_* policies removed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops through storage files with glee,
Locking down paths for privacy's decree!
Users own their folders, photos shine and gleam,
While agents' avatars are shared by the dream. 🐰🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'fix: add storage RLS policies for 360ghar-storage bucket' accurately and specifically describes the main change: adding RLS policies to the storage bucket to resolve upload failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/storage-rls-policies

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@supabase/migrations/20260516000000_configure_storage_rls_policies.sql`:
- Around line 14-15: Remove the manual-only note and convert the out-of-band
step into a proper SQL migration under supabase/migrations/ (so it runs via
supabase db push); add statements to enable RLS and create/replace the necessary
policies for the storage.objects table (e.g., ALTER TABLE storage.objects ENABLE
ROW LEVEL SECURITY; CREATE OR REPLACE POLICY "<policy_name>" ON storage.objects
FOR SELECT USING (<condition>) WITH CHECK (<condition>); and any required
GRANTs), ensuring the migration file name follows the existing timestamped
pattern and contains the full DDL/DDL POLICY changes so no manual Dashboard SQL
Editor step is required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e43384b1-76e8-4af2-b3ca-5b986ddfd4e2

📥 Commits

Reviewing files that changed from the base of the PR and between 670dd10 and 7630275.

📒 Files selected for processing (1)
  • supabase/migrations/20260516000000_configure_storage_rls_policies.sql

Comment on lines +14 to +15
-- ⚠️ Run this via the Supabase Dashboard SQL Editor
-- (SQL migrations lack owner permissions on storage.objects).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don't ship this as a manual-only migration.

Documenting an out-of-band SQL Editor step here makes the change non-reproducible and easy to miss in later environments. Please rework this so the RLS policies are applied by the normal migration path instead of requiring a separate manual run after merge.

As per coding guidelines, supabase/migrations/**/*: All migrations must be placed in supabase/migrations/ and applied via supabase db push

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/migrations/20260516000000_configure_storage_rls_policies.sql` around
lines 14 - 15, Remove the manual-only note and convert the out-of-band step into
a proper SQL migration under supabase/migrations/ (so it runs via supabase db
push); add statements to enable RLS and create/replace the necessary policies
for the storage.objects table (e.g., ALTER TABLE storage.objects ENABLE ROW
LEVEL SECURITY; CREATE OR REPLACE POLICY "<policy_name>" ON storage.objects FOR
SELECT USING (<condition>) WITH CHECK (<condition>); and any required GRANTs),
ensuring the migration file name follows the existing timestamped pattern and
contains the full DDL/DDL POLICY changes so no manual Dashboard SQL Editor step
is required.

Comment on lines +40 to +47
USING (
bucket_id = '360ghar-storage'
AND auth.uid() IS NOT NULL
AND name ~ ('^users/' || auth.uid()::text || '/[^/]+/[^/]+$')
);

-- ── UPDATE: authenticated users can update their own files ──
DROP POLICY IF EXISTS "users_update_own" ON storage.objects;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing cross-user SELECT for chat photos

The users_select_own policy only grants SELECT to the file owner (auth.uid() matches). When a chat recipient tries to display a received photo at users/{sender_uid}/chats/{filename}, they get an RLS denial because their UID doesn't match. An authenticated_read_chats policy (mirroring authenticated_read_listings) is needed unless all chat photo reads are exclusively mediated by backend-generated signed URLs (service role bypasses RLS). The PR description and existing SELECT comment say Flutter calls createSignedUrl itself, which also requires SELECT on the object.

Comment on lines +66 to +67
bucket_id = '360ghar-storage'
AND auth.uid() IS NOT NULL
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security 10-year signed URL expiry is functionally a permanent public link

The comment "signed URLs (10-year expiry) as a fallback" describes a URL that effectively never expires. If one of these URLs leaks via logs, browser history, a forwarded message, or a bug that exposes the URL in an API response, the file remains accessible indefinitely to anyone with the URL, defeating the private bucket and the RLS policies. Consider using much shorter expiries (hours or days) with a backend endpoint to regenerate signed URLs on demand.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Requires human review: This is a SQL migration that adds RLS policies on storage.objects, which is a security-sensitive database change with potential to break image uploads across the app, so it requires human review.

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant