Skip to content

feat(store): user organizations search skips soft-deleted rows - #1947

Merged
AmanGIT07 merged 3 commits into
mainfrom
soft-delete-user-orgs-reads
Sep 25, 2026
Merged

AmanGIT07 merged 3 commits into
mainfrom
soft-delete-user-orgs-reads

Conversation

@AmanGIT07

Copy link
Copy Markdown
Contributor

Fifth of the org view repositories. Follows #1945 and #1946.

Summary

The user organizations search leaves out soft-deleted organizations, policies, roles, and users. It also drops the last copy of the deleted_at column constant.

Changes

  • The base query starts from fromLive(policies) and adds live on the joined roles, organizations, and users.
  • The project count subquery uses fromLive(projects) in place of its hand-written null check. It already skipped soft-deleted projects.
  • COLUMN_DELETED_AT is removed. Its last two uses, in the user projects query, move to the live helper and build byte-identical SQL, so no pinned test changed. feat(store): user projects search skips soft-deleted rows #1945 makes the same two-line change, so the branches merge cleanly in either order.
  • New docker-backed suite user_orgs_repository_pg_test.go: seeds a soft-deleted organization, grant, role, user, and project, then checks the listing, the reported roles, and the project count.

Technical Details

This query already joined users, so filtering there means a soft-deleted user gets an empty list, the same answer as a user id nobody owns. The user projects search has no such join and is unaffected.

Frontier does not set deleted_at on these tables yet, so the search returns the same rows as before.

Test Plan

  • go test -run 'TestUserOrgsRepository' ./internal/store/postgres/ passes (unit tests and the new suite)
  • The new suite fails on main
  • golangci-lint run ./internal/store/postgres/... reports no issues
  • End to end against a local server through AdminService/SearchUserOrganizations. Three orgs, two members, a custom role and three projects were created through the public RPCs, then deleted_at was set by SQL. The same scenarios ran against main on the same database, with only the binary swapped.
# Scenario This branch main
1 Baseline before any soft delete: three orgs, three projects, two roles PASS PASS
2 The soft-deleted org is not listed PASS FAIL
3 The org whose grant is soft-deleted is not listed PASS FAIL
4 Only the live org is listed PASS FAIL
5 The soft-deleted role is not in role_names PASS FAIL
6 project_count skips the soft-deleted project PASS PASS
7 A soft-deleted user is in no org PASS FAIL
8 A user id nobody owns is in no org PASS PASS

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.

The search reads policies, roles, organizations, and users through the
live-row helpers. The project count already skipped deleted projects and
now uses the helper too.
Its last two uses move to the live helper, which builds the same SQL.
…h soft-deleted rows

Seeds a soft-deleted organization, grant, role, user, and project, then
checks the listing, the reported roles, and the project count.
@vercel

vercel Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
frontier Ready Ready Preview Sep 25, 2026 6:11am UTC

@coderabbitai

coderabbitai Bot commented Sep 25, 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: c89c63e7-d6f5-4d75-80f9-8d4b3eb3fb5f

📥 Commits

Reviewing files that changed from the base of the PR and between 057a60c and a9d270a.

📒 Files selected for processing (5)
  • internal/store/postgres/org_users_repository.go
  • internal/store/postgres/user_orgs_repository.go
  • internal/store/postgres/user_orgs_repository_pg_test.go
  • internal/store/postgres/user_orgs_repository_test.go
  • internal/store/postgres/user_projects_repository.go

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Organization search now excludes archived organizations, users, roles, and access grants.
    • Project totals no longer include archived projects.
    • Archived users no longer see organizations in search results, keeping results and counts consistent with active records.

Walkthrough

PostgreSQL user organization and project queries now use live-row helpers to filter soft-deleted records. The changes also remove an exported constant and add SQL expectation updates and Docker-backed integration tests for search results.

Changes

PostgreSQL repository filtering

Layer / File(s) Summary
Soft-delete filtering in repository queries
internal/store/postgres/user_orgs_repository.go, internal/store/postgres/user_projects_repository.go, internal/store/postgres/org_users_repository.go, internal/store/postgres/user_orgs_repository_test.go
User organization and project queries use live-row helpers. SQL expectations include soft-delete filters. The exported COLUMN_DELETED_AT constant is removed.
PostgreSQL search tests
internal/store/postgres/user_orgs_repository_pg_test.go
Docker-backed tests check that search excludes soft-deleted organizations and grants, returns only live roles, excludes soft-deleted projects from counts, and returns no organizations for a soft-deleted user.

Priority: ⬇️ Low

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

Change: Bug fix

Merge Risk: ⚪ Minimal · up to a9d27

The search changes and their PostgreSQL tests present no identified issue requiring resolution before merge.

Security Architecture Review

Security architecture risk: 🔵 Low · up to a9d27

The search now hides soft-deleted records without adding an entrypoint or widening access. An empty organization listing should not, however, be treated as proof that every other user-scoped read has been revoked.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed organization read can reduce the memberships and roles returned for a requested user. It does not itself delete grants or change the authority of other read paths.

Trust Boundaries and Controls

  • observed — The public handler accepts a requested user ID and delegates to the existing search path. The repository uses that ID as a prepared-query parameter and adds deleted-row restrictions rather than an attacker-controlled query fragment.

Hardening Proposals

  • proposed — If deleting a user is intended to revoke all user-scoped visibility, define and enforce that invariant across authorization and read paths; do not infer revocation from an empty organization listing alone.
🚥 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.

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 36101719227

Coverage increased (+0.1%) to 51.89%

Details

  • Coverage increased (+0.1%) from the base build.
  • Patch coverage: 7 of 7 lines across 2 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: 41135
Covered Lines: 21345
Line Coverage: 51.89%
Coverage Strength: 16.91 hits per line

💛 - Coveralls

This branch was successfully deployed

1 active deployment
Preview — a9d270aa Deployed Sep 25, 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