Scope all controller account lookups by CompanyId (defense-in-depth sweep)
Completes the read-path defense-in-depth pass flagged in the accounting audit:
every Accounts lookup in a controller now carries an explicit CompanyId predicate,
matching the standing rule in CLAUDE.md ("every FindAsync/GetAllAsync must include
an explicit CompanyId"). ~19 lookups across 12 controllers:
- Tier 1 (write-path): AccountsController duplicate account-number check (Create/Edit)
- Tier 2 (dropdowns/lists): Accounts (Index/year-end/parent), BankReconciliations,
Bills (bank list + receipt scan + suggest), Budgets, CatalogItems, Expenses,
FixedAssets, Inventory, JournalEntries chart dropdown, Vendors
- Tier 3 (accountIds.Contains display maps): JournalEntries/Reports/VendorCredits
detail views, scoped via the in-scope entity's CompanyId for uniformity
companyId source per controller: _tenantContext where available, else the in-scope
entity's CompanyId, else the current user. Build clean; 291 unit tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -132,7 +132,7 @@ public class VendorCreditsController : Controller
|
||||
.Select(l => l.AccountId!.Value)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
var accounts = await _unitOfWork.Accounts.FindAsync(a => accountIds.Contains(a.Id));
|
||||
var accounts = await _unitOfWork.Accounts.FindAsync(a => a.CompanyId == vc.CompanyId && accountIds.Contains(a.Id));
|
||||
ViewBag.AccountMap = accounts.ToDictionary(a => a.Id, a => $"{a.AccountNumber} – {a.Name}");
|
||||
|
||||
// Load bills referenced by applications
|
||||
@@ -357,8 +357,9 @@ public class VendorCreditsController : Controller
|
||||
|
||||
private async Task PopulateDropdownsAsync()
|
||||
{
|
||||
var companyId = _tenantContext.GetCurrentCompanyId() ?? 0;
|
||||
var vendors = await _unitOfWork.Vendors.FindAsync(v => v.IsActive);
|
||||
var accounts = await _unitOfWork.Accounts.FindAsync(a => a.IsActive);
|
||||
var accounts = await _unitOfWork.Accounts.FindAsync(a => a.CompanyId == companyId && a.IsActive);
|
||||
|
||||
ViewBag.VendorList = vendors
|
||||
.OrderBy(v => v.CompanyName)
|
||||
|
||||
Reference in New Issue
Block a user