Skip to content

feat(store): org scoped searches report nothing for a deleted organization - #1953

Merged
AmanGIT07 merged 2 commits into
mainfrom
fix-org-scoped-searches-live-org
Sep 29, 2026
Merged

AmanGIT07 merged 2 commits into
mainfrom
fix-org-scoped-searches-live-org

Conversation

@AmanGIT07

@AmanGIT07 AmanGIT07 commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Follows #1946, #1947, #1949 and #1951, which added this check as they were written. This brings the three searches that merged before we agreed on it into line.

Summary

The org users, org projects and user projects searches never read the organizations table. A soft-deleted organization still returned its rows, while an organization id nobody owns returned nothing. Those two now agree.

Changes

  • Each of the three joins organizations and adds live on it. The join is on the organizations primary key, so it matches at most one row and cannot duplicate results.
  • The user projects join goes inside the subquery that picks the projects, aliased o2 to match that file.
  • New docker-backed suite search_live_org_pg_test.go: the same shape is seeded under a live organization and a soft-deleted one, and each search is checked against both.

Technical Details

Nothing upstream catches this for these three. They authorize with IsSuperUser, so the disabled-organization gate in IsAuthorized never runs, and that gate steps aside for platform superusers anyway. None of their handlers resolve the organization first.

The organization service users search is deliberately untouched. Its handler resolves the organization through a lookup that reads live rows only, so a deleted organization is already not found before the query runs.

The organization personal access tokens search has the same gap and is also untouched. It is not one of the searches this series raised PRs for, and its users join needs the same filter, so it is handled with the PAT soft delete work rather than piecemeal here.

The organization tokens search is also untouched. It has no soft-delete filters on any of its three tables, so it gets the whole treatment as its own change rather than the organization half here.

The seeded user and organizations carry avatars because two of these queries cannot scan a null one. That is pre-existing and noted in the test.

Frontier does not set deleted_at on organizations yet, so the searches return the same rows as before.

Test Plan

  • go test ./internal/store/postgres/ passes
  • The new suite fails on main for all three searches
  • golangci-lint run ./internal/store/postgres/... reports no issues
  • End to end against a local server. An organization, a project, a member and grants on both were created through the public RPCs, then the organization was soft-deleted by SQL. The same checks ran against main on the same database, with only the binary swapped.
Check main this branch
Before the delete, all three searches report rows PASS PASS
Deleted organization, SearchOrganizationUsers FAIL, 2 rows PASS, 0 rows
Deleted organization, SearchOrganizationProjects FAIL, 1 row PASS, 0 rows
Deleted organization, SearchUserProjects FAIL, 1 row PASS, 0 rows

SQL Safety

  • Values flow through ? placeholders, goqu.Ex{}, or goqu.Record{} — never fmt.Sprintf or + building a query that gets executed.
  • ToSQL() callers capture and forward params (query, params, err := stmt.ToSQL(); db.…Context(ctx, …, query, params...)). Never query, _, err := ….
  • No ? placeholders inside single-quoted SQL literals in goqu.L.
  • No new //nolint:forbidigo or // #nosec G20x annotations.

…ation

The org users, org projects, and user projects searches join organizations
and filter it, so a soft-deleted organization answers the same way as an
organization id nobody owns.
… scoped searches

Seeds the same shape under a live organization and a deleted one, so an
empty result cannot come from a broken seed.
@vercel

vercel Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
frontier Error Error Sep 28, 2026 6:50am UTC

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: raystack/frontier/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 17f5076d-11c1-43e0-b235-b4c586637e49

📥 Commits

Reviewing files that changed from the base of the PR and between 8c18295 and 45a3a72.

📒 Files selected for processing (7)
  • internal/store/postgres/org_projects_repository.go
  • internal/store/postgres/org_projects_repository_test.go
  • internal/store/postgres/org_users_repository.go
  • internal/store/postgres/org_users_repository_test.go
  • internal/store/postgres/search_live_org_pg_test.go
  • internal/store/postgres/user_projects_repository.go
  • internal/store/postgres/user_projects_repository_test.go

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Organization search results now exclude projects and users associated with deleted organizations, keeping results limited to active organizations.

Walkthrough

The three PostgreSQL search query paths now require a matching live organization. SQL expectations and database-backed tests cover live and soft-deleted organizations.

Changes

Live organization search filtering

Layer / File(s) Summary
Filter search results by live organization
internal/store/postgres/org_users_repository.go, internal/store/postgres/org_users_repository_test.go, internal/store/postgres/org_projects_repository.go, internal/store/postgres/org_projects_repository_test.go, internal/store/postgres/user_projects_repository.go, internal/store/postgres/user_projects_repository_test.go, internal/store/postgres/search_live_org_pg_test.go
Organization-user, organization-project, and user-project queries now join or filter against live organizations. SQL expectations reflect the added conditions. PostgreSQL integration tests verify results for live and soft-deleted organizations.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 45a3a

The searches are set to exclude results for soft-deleted organizations, with tests covering live and deleted cases. No issue identified here prevents merging after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 45a3a

The reviewed queries add a condition that removes results for deleted organizations while retaining their existing organization and policy filters. No expanded access was identified. Coverage of other organization-scoped paths remains incomplete.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The direct visibility change is confined to results selected under an organization whose row is soft-deleted. The reviewed predicates do not introduce a way to select a different organization.

Trust Boundaries and Controls

  • inferred — For user-project search, a caller can supply target user and organization IDs only after the existing superuser route check; the added organization predicate narrows, rather than broadens, the repository result set. Authorization on the other related entrypoints was not independently established in this review.
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
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.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR

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.

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 36388354390

Coverage increased (+0.02%) to 52.214%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 15 of 15 lines across 3 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 41179
Covered Lines: 21501
Line Coverage: 52.21%
Coverage Strength: 17.07 hits per line

💛 - Coveralls

@rohilsurana

Copy link
Copy Markdown
Member

OrgPATsRepository.Search has the same gap as the three searches fixed here, and the description does not mention it.

Its base query at internal/store/postgres/org_pats_repository.go:134 filters on p.org_id = orgID and p.deleted_at IS NULL only. There is no organizations join. And SearchOrganizationPATs at internal/api/v1beta1connect/organization_pats.go:42 passes request.Msg.GetOrgId() straight to the service without resolving the organization first. So a soft-deleted organization still reports its PATs.

The description says why org service users and org tokens are left alone. I checked both and agree with the reasoning. Org pats needs the same note, or the same fix.

One more thing in that file while you are in there. The users join at line 136 is a LEFT JOIN with no u.deleted_at IS NULL check, so a soft-deleted user's PATs still come back carrying their name and email. That looks like it belongs with the org tokens follow-up rather than this PR.

@AmanGIT07

Copy link
Copy Markdown
Contributor Author

Right on both, thanks.

Org pats has the same gap. It was in an earlier revision of this branch and came out again deliberately, because this PR is scoped to the searches this series raised PRs for and org pats is not one of them. I should have said that in the description rather than leaving it silent. Added now.

It will be tested and fixed with the PAT soft delete work rather than here, along with the users join you spotted. That join has the same shape as the org tokens one: a soft-deleted user's tokens still come back carrying their name and email.

Worth recording while we are here. DeleteOrganization has no PAT step at all. Those rows disappear today only because user_pats.org_id carries ON DELETE CASCADE and the org row is still hard-deleted. Soft delete turns that off silently, so a deleted org's tokens stay live with deleted_at null and nothing sets it. Same for domains.org_id. That is noted on the org soft-cascade ticket.

@rohilsurana rohilsurana left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Description covers org pats now, thanks. Handling it with the PAT soft delete work makes sense, since the users join needs fixing in the same place.

One non-blocking note on the description, for whoever reads this later. "Frontier does not set deleted_at on organizations yet, so the searches return the same rows as before" holds for the two project searches but not for org users. projects.org_id has a foreign key to organizations(id) with no ON DELETE clause, so an organization with any project row cannot be hard-deleted and that join can never drop a row. policies.resource_id is a bare uuid NOT NULL with no foreign key, because it is polymorphic. So a hard-deleted organization leaves its membership policies behind, and SearchOrganizationUsers on that dead id used to return them. Now it returns nothing.

That is an improvement, not a regression. It just means this PR changes behaviour on today's data too, rather than only guarding a future soft delete.

Merged this with #1952 locally. No conflicts, and both docker suites pass together.

@AmanGIT07
AmanGIT07 merged commit 397098b into main Sep 29, 2026
7 of 8 checks passed
@AmanGIT07
AmanGIT07 deleted the fix-org-scoped-searches-live-org branch September 29, 2026 05:58

This branch had an error being deployed

1 failed deployment
Preview — 45a3a724 Deployed Sep 28, 2026 by vercel[bot]
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.

3 participants