Skip to content

issues: queue the #Z61JRT public-bucket RLS correction - #2563

Merged
BigSimmo merged 3 commits into
mainfrom
claude/issues-z61jrt-rls-correction
Sep 2, 2026
Merged

issues: queue the #Z61JRT public-bucket RLS correction#2563
BigSimmo merged 3 commits into
mainfrom
claude/issues-z61jrt-rls-correction

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

Queues one correction request. The archived #Z61JRT close outcome carries a security claim that is wrong in the unsafe direction, and this files the correction of record against it.

The error. That outcome states: "Flipping the bucket would also not have produced a working read path: the storage RLS policy 'image storage owner read' keys on the first path segment equalling auth.uid(), which a published ownerless document never satisfies, so signed URLs minted with the service-role key are the only mechanism that serves public-corpus figures."

Why it is wrong. The owner-folder policy on storage.objects governs authenticated reads of a private bucket and has no bearing on a public one. The installed client documents getPublicUrl at node_modules/@supabase/storage-js/src/packages/StorageFileApi.ts as requiring buckets table permissions: none and objects table permissions: none. A public bucket therefore serves its objects to anyone holding the URL, with no RLS evaluated and no token. If clinical-images were ever flipped to public, every object in it would become anonymously readable — which is precisely the hazard #Z61JRT existed to record. The archived text inverts that risk and would invite a reader to believe a bucket flip is inert.

Why it is filed as a new row rather than edited. Archived rows are immutable history here: updateIssue refuses them outright, and check:ledger-write-discipline rejects direct table-row edits and any canonical diff that does not match its recorded reconciliation transaction. Deleting the sentence would also destroy the audit trail the ledger exists to keep. So the correction is a new open P2 row that quotes the erroneous sentence, gives the evidence, and states explicitly that anyone reading the archived outcome must read the correction with it.

A second error, caught in review and fixed before reconciliation. The first draft of this row asserted that a manual dashboard flip would be "reverted by the next migration run". That was also false, and false in the same containment-overstating direction as the error the row exists to correct. scripts/check-migration-history-alignment.ts computes localOnly = [...local].filter((version) => !remote.has(version)) and labels exactly that set "pending apply", so a version already recorded in remote history never runs again; 20260717139000's on conflict (id) do update set public = false fires only when that migration itself executes — a fresh replay such as a local db reset or the CI migration-replay job — not against the live project on an ordinary deploy. Fixed in fd6b5aecb, so the ledger never carries it. The row now records both errors and how each was caught.

The real control is detection, not prevention. If clinical-images were flipped in the dashboard it would stay public until a person restored it. schema_drift_snapshot captures storage_buckets, so npm run check:drift and the post-merge live-drift workflow would surface the changed public value as drift — but check:drift only reports and repairs nothing. Remediation is manual: flip it back, or ship a NEW migration re-asserting public = false, since only a new version would be pending and therefore actually execute.

No code fix is owed, and nothing is exposed. The bucket was not flipped: a user-authorised read-only query on 2026-09-02 returned storage.buckets.public = false for both clinical-images and clinical-documents. The shipped route change is unaffected — it signs uniformly through createSignedUrls, never calls getPublicUrl, and a repo-wide grep for getPublicUrl returns zero matches. What was wrong was the stated reason a bucket flip would be harmless, not the conclusion that the bucket must stay private.

Provenance. Both errors were raised as P2 findings by the Codex reviewer — the first on #2559, the second on this PR — and each was verified against the repository's own source (storage-js remarks; check-migration-history-alignment.ts) rather than accepted on assertion. The original claim came from a schema review earlier in the same session and was carried into the close outcome unchecked.

This PR only queues the request; it does not touch the canonical ledger. Reconciliation happens in a later run, as the write-discipline gate requires (a request must land as pending in one PR and be applied in a later one).

Verification

  • npm run verify:pr-local
PR-local verification summary:
- completed: check:runtime, check:installed-lock-parity, format:changed, sitemap:check,
  check:repo-awareness-snapshot, docs:check-index, docs:check-inventory, docs:check-scripts,
  docs:check-links, check:branch-review-ledger, check:outstanding-issues,
  check:ledger-write-discipline
- failed: (none)
- not reached: (none)

Decisive lines: Ledger write discipline passed for f74715b6fcf6..HEAD and [snapshot] in step with data/outstanding-issues-snapshot.json. Re-run after the fd6b5aecb rewrite and still clean. Scope was classified as recognised low-risk, so lint, typecheck, the unit suite and the build were skipped by the router rather than by choice. npm run format reported every file unchanged.

  • UI verification not run: no UI, routing, styling, or browser behaviour changed.
  • npm run verify:release not run: not a release or handoff confidence claim.
  • Retrieval and answer-generation evals not run: no executable product scope in the diff.

Risk and rollout

  • Risk: Very low. One new immutable request file under docs/outstanding-issues-inbox/. No source, schema, migration, workflow, or configuration file is touched, and the canonical ledger is not edited.
  • Rollback: Revert the commits. Nothing has been applied to docs/outstanding-issues.md, so no reconciliation needs undoing.
  • Provider or production effects: None. The live readings quoted above were taken earlier under explicit user authorisation and were select statements only; this PR runs nothing against any provider.
  • RAG impact: no retrieval behaviour change — a single queued ledger request. No file under src/lib/rag/, no retrieval RPC, no ranking configuration, no golden fixture and no ranking test is touched.

Clinical Governance Preflight

The diff queues one ledger request and does not touch ingestion, answer generation, search/ranking, source rendering, document access, privacy, production environment, or clinical output. It is completed in full because the subject matter is document-access security, and each statement was checked against the tree rather than assumed.

  • Source-backed claims still require linked source verification before clinical use. Unchanged: no answer, citation, or source-rendering code is touched.
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval. No ingestion, upload, or document workflow is added, widened, or altered.
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy). No environment value or Supabase configuration is modified; the readings quoted were taken against that project reference and no other, and the stale qjgitjyhxrwxsrydablr was not used.
  • Service-role keys and private document access remain server-only. This PR exists to keep that true in the record: it corrects a claim that understated the consequence of making an image bucket public, and a second claim that overstated the automation guarding it. Both buckets remain private on live, and image access still runs through server-minted signed URLs.
  • Demo/synthetic content remains clearly separated from real clinical sources. No demo fixture or demo branch is modified.
  • Source metadata, review status, and outdated/unknown-source behaviour remain conservative. No metadata construction, governance, or review-status code is touched.
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behaviour changed. No clinical decision-support behaviour changed, so the classification is unaffected.

Notes

Merge order does not matter. This PR only adds a pending request, and #2559 only applies requests that were already pending on main, so the two do not conflict and neither blocks the other. Whichever lands second, the correction row is created by the next reconciliation run.

A follow-up reply on #2559's resolved thread corrects the same false auto-reversion sentence where I had repeated it there, so neither thread stands as a record of it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AcjoJHKAPfBPKYgwTF3wTS


Note

Low Risk
Documentation-only inbox queue with no runtime, schema, or ledger reconciliation in this PR.

Overview
Adds a single pending outstanding-issues inbox request (ac026ec0-6070-4623-aecc-c9a1af2f312a.json) with action: "add" — it does not edit docs/outstanding-issues.md or any application code.

The queued P2 issue documents a correction of record for archived #Z61JRT: the close outcome wrongly implied that flipping clinical-images to public would be blocked or inert because owner-folder RLS would still apply. The request states the accurate risk (a public bucket serves objects anonymously with no RLS), notes live buckets remain private and signing paths are unchanged, and clarifies that migration ON CONFLICT … public = false only applies on fresh migration replay — not as automatic reversion on live — with detection via check:drift and manual remediation as the real control.

Provenance ties the finding to Codex review on PR #2559 (verified against storage-js getPublicUrl docs) and a draft auto-reversion claim fixed before reconciliation.

Reviewed by Cursor Bugbot for commit d4ce626. Configure here.

The archived #Z61JRT close outcome asserts that flipping the clinical-images
bucket to public would still not produce a working read path, because the
"image storage owner read" RLS policy keys on the first path segment
equalling auth.uid(). That is wrong, and wrong in the unsafe direction.

The installed client documents getPublicUrl as requiring "buckets table
permissions: none" and "objects table permissions: none"
(node_modules/@supabase/storage-js/src/packages/StorageFileApi.ts). A public
bucket serves its objects with no RLS evaluated and no token, so flipping
clinical-images would make every object anonymously readable by URL — the
exact hazard the original row existed to warn about.

Archived rows are immutable history: updateIssue refuses them and
check:ledger-write-discipline rejects direct table-row edits. The correction
is therefore filed as a new open P2 row that quotes the erroneous sentence,
gives the evidence, and states that the archived outcome must be read with it.

No code fix is owed. The bucket was not flipped — a read-only query on
2026-09-02 returned public = false for both buckets, and
20260717139000_create_storage_buckets.sql re-asserts that on every replay —
and the shipped route signs uniformly via createSignedUrls, with zero
getPublicUrl matches repo-wide.

Raised by the Codex reviewer on PR #2559 and verified against the installed
source rather than accepted on assertion.

This PR only queues the request. Reconciliation happens in a later run, as
the write-discipline gate requires.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AcjoJHKAPfBPKYgwTF3wTS
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 6c0b97d0-0b3e-4319-94a0-31aca8930b1d


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.

@supabase

supabase Bot commented Sep 2, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@BigSimmo
BigSimmo marked this pull request as ready for review September 2, 2026 10:46
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T10:52:54.543612Z abd3d48 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_6381a61a-d704-4488-8e91-3a7443aeca3d)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: abd3d48c6e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/outstanding-issues-inbox/ac026ec0-6070-4623-aecc-c9a1af2f312a.json Outdated
@BigSimmo
BigSimmo enabled auto-merge (squash) September 2, 2026 15:28
@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_61abe0a3-1653-45a7-a5e5-39092a345f09)

@BigSimmo
BigSimmo merged commit 940a6cd into main Sep 2, 2026
29 of 33 checks passed
@BigSimmo
BigSimmo deleted the claude/issues-z61jrt-rls-correction branch September 2, 2026 15:30
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.

2 participants