fix(family-sharing): scope form + import account lists to accessible_accounts (#1803)#1989
Conversation
📝 WalkthroughWalkthroughThe PR scopes account lists to the current user's ChangesPer-user Account Access Control
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
b57feb6 to
6e328ff
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@test/controllers/transactions_controller_test.rb`:
- Around line 392-393: The assertions call refute_includes on response.body (a
String) with integer needles (accounts(:investment).id and accounts(:loan).id),
which can raise TypeError; change the needles to strings (e.g.
accounts(:investment).id.to_s and accounts(:loan).id.to_s or
"#{accounts(:investment).id}") so refute_includes response.body, <id>.to_s is
used for both checks.
In `@test/controllers/transfers_controller_test.rb`:
- Around line 21-23: The assertions are comparing integers to response.body (a
String), causing a TypeError; update the three assertions that reference
accounts(:depository).id, accounts(:investment).id, and accounts(:loan).id so
they compare string values (e.g., call to_s or use string interpolation) when
calling assert_includes and refute_includes against response.body to ensure the
types match.
🪄 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: 68134a64-b75f-4685-8a53-48edf60e1e4d
📒 Files selected for processing (7)
app/controllers/transactions_controller.rbapp/views/import/uploads/show.html.erbapp/views/transactions/_form.html.erbapp/views/transfers/_form.html.erbtest/controllers/import/uploads_controller_test.rbtest/controllers/transactions_controller_test.rbtest/controllers/transfers_controller_test.rb
There was a problem hiding this comment.
🧹 Nitpick comments (1)
test/controllers/transactions_controller_test.rb (1)
383-394: 💤 Low valueConsider adding a positive assertion for accessible accounts.
The test verifies that inaccessible accounts are not exposed, but does not confirm that at least one accessible account IS included. The transfers test includes
assert_includes response.body, accounts(:depository).id.to_sfor this purpose.✅ Optional enhancement
assert_response :success + assert_includes response.body, accounts(:depository).id.to_s refute_includes response.body, accounts(:investment).id.to_s refute_includes response.body, accounts(:loan).id.to_s🤖 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 `@test/controllers/transactions_controller_test.rb` around lines 383 - 394, In the test "new only exposes account ids accessible to the signed-in user" add a positive assertion that at least one permitted account is present in the response (e.g. assert_includes response.body, accounts(:depository).id.to_s) so the test both rejects inaccessible accounts and confirms accessible ones are included; you can also add assert_includes for accounts(:credit_card).id.to_s if you want to assert multiple visible accounts.
🤖 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.
Nitpick comments:
In `@test/controllers/transactions_controller_test.rb`:
- Around line 383-394: In the test "new only exposes account ids accessible to
the signed-in user" add a positive assertion that at least one permitted account
is present in the response (e.g. assert_includes response.body,
accounts(:depository).id.to_s) so the test both rejects inaccessible accounts
and confirms accessible ones are included; you can also add assert_includes for
accounts(:credit_card).id.to_s if you want to assert multiple visible accounts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a6cec951-e711-47e2-ad77-739a30a80238
📒 Files selected for processing (2)
test/controllers/transactions_controller_test.rbtest/controllers/transfers_controller_test.rb
|
Good security fix — targeted and well-tested. A couple of observations: Efficiency bonus: The switch from
Test pattern: The
Generated by Claude Code |
Summary
Closes part of #1803 (the UI leak half).
Non-admin family members could see ids, currencies, and names of accounts the family admin owns but has not shared with them. The account detail routes already enforced access (unshared accounts 404), but several form-render paths still embedded the full
Current.family.accountslist in the page.app/views/transfers/_form.html.erb:1— JSON map of every family account id + currency for the JS currency-difference check.app/views/transactions/_form.html.erb:3— same pattern.app/views/import/uploads/show.html.erb:59, 115, 147— QIF and CSV upload account dropdowns. The matchingImport::UploadsController#updatealready usedaccessible_accounts.find(...), so this was a pure UI leak.app/controllers/transactions_controller.rb:374(exchange_rate) — found by family scope instead of user scope. The action isn't currently routed (the live endpoint isExchangeRatesController#show), but tightened for defense in depth.All four switch to the existing
accessible_accountshelper, which delegates toCurrent.user.accessible_accounts(owned + shared viaAccountShare).Out of scope
The second half of #1803 — integration tokens (Plaid / EnableBanking / SimpleFIN / Lunchflow
*_items) being scoped tofamily_idinstead ofuser_id, so members overwrite each other's sessions — needs a schema change, backfill, and controller/view rework. Tracking it as a follow-up rather than mixing it into this PR.Provider-item controllers
The audit also found
Current.family.accounts.find(params[:account_id])in many*_items_controller.rbfiles (plaid, simplefin, enable_banking, snaptrade, ibkr, sophtron, indexa_capital, mercury, lunchflow, brex, coinbase, binance, kraken). Every one of those controllers hasbefore_action :require_admin!, so they're not reachable by the non-admin member described in the bug. Tightening them is a separate hardening pass.Test plan
bin/rails test test/controllers/transfers_controller_test.rb— new test"new only exposes accounts accessible to the signed-in user"passes.bin/rails test test/controllers/transactions_controller_test.rb— new test"new only exposes account ids accessible to the signed-in user"passes.bin/rails test test/controllers/import/uploads_controller_test.rb— new test"csv upload dropdown only lists accounts accessible to the signed-in user"passes.bin/rails testbin/rubocop -f github -abundle exec erb_lint ./app/**/*.erb -abin/brakeman --no-pagerSummary by CodeRabbit
Bug Fixes
Tests