Repository navigation
refactor(farm): put farm settings behind an IFarmModule contract - #1015
Conversation
Login establishes identity before TenantContext exists, so its farm-code lookup moves behind the Platform identity port instead of reaching Farm's IAccountRepository from the endpoint. Same query, same check order, same error codes and statuses.
Account, settings, logo and banner endpoints, the expense and customer-balance currency reads and the simulation seeder reach Farm through IFarmModule. FarmClock and peer modules keep IAccountRepository as the stable account seam. Closes #851
|
Review of record: Codex Review of PR #1015Reviewed FindingsP2 · CONFIRMED · Guard integration defect, not a product defect
Failure scenario: merge #1013 and #1015 without reconciling the exceptions, in either order, and Evidence: fetched #1013 at Coordinate the reconciliation in whichever PR lands second. Preserve the approved identity/account seam; moving login or the currency lock behind Interaction with PR #1013: measured countsFarm owns exactly Five Infrastructure members read genuinely Farm-owned tables without an allowance. All five read
The actual scanner reports 12 Infrastructure entries, not five: it additionally classifies seven This happens because #1013 resolves ownership from the entity's CLR namespace, The scanner also walks projects referencing Infrastructure and reports four API entries:
Thus the unmodified combined guard needs 16 new rows: 12 Infrastructure plus 4 API. Correcting its table ownership handling would leave 8 genuine Farm exceptions, comprising the five Infrastructure members and three API account readers. #1013's expiry field is an issue trigger, Login parityCompared the entire endpoint and identity path against the base, not just the new wrapper.
The existing security tests were unmodified except for the two permitted decorator pass-throughs. Executed suite counts include lockout 5, suspension 16, ambient-login principal 6, auth cookies 6, step-up authentication 45, credential epoch 14, epoch races 9, epoch middleware order 3, must-change-password 5, first-run notice 4 and login counter probe 1. All passed. The broader selected run also exercised auth body limits, validation, logging and limiter paths. Other behavior and contract checksSettings, logo and banner route metadata and authorization are unchanged: settings reads/writes and branding mutations remain Owner-only; the account and image reads remain available to authenticated roles. Validation, timezone rejection, failure/status mapping, upload limits, sanitization, ETags, conditional requests and content hashes still reach their original implementations. Existing mutation handlers retain their All 16 The six listed Farm contract types cover the approved interface, command and result records without exposing entities or EF types. Three independent temporary mutations produced the expected failures:
Logs: Verification
Integration commands used NitsP3 · CONFIRMED · Documentation only. Verdict: No product blocker in #1015; resolve the confirmed guard incompatibility before #1013 and #1015 both land. |
|
Fixed Astra round 1's P3 in |
Closes #851
Epic #514, Track C slice 9. Farm settings, logo and banner now sit behind an
IFarmModulecontract, the second after Finance (#849). Tenant identity stays in Platform. No route, response, status or schema changes.Scope decisions (owner-approved at the design checkpoint)
IFarmModulereads the current farm's settings asFarmSettingsDetails, reports whether the currency may still change, writes settings throughUpdateFarmSettingsCommand, and reads, sets and removes the logo and banner.FarmModuleonly forwards to the existing repositories and handlers.owners.Farm.contractlistsIFarmModule,FarmSettingsDetails,FarmBrandingHashes,FarmLogoMetadata,FarmLogoContentandUpdateFarmSettingsCommand.ExpenseEndpoints.ListExpensesandPaymentEndpoints.ListCustomerBalances(currency label) andSimulationDataSeeder(timezone phase).IIdentityProvider.ResolveFarmCodeAsync, not the Farm contract. That lookup establishes identity beforeTenantContextexists, soIFarmModulemust not run it.IdentityProviderimplements it with theIAccountRepositoryit already holds. The query (FindBySlugAsync), the check order (farm code, then suspended, then credentials), the error codes and the statuses are unchanged. Each branch does the same database work as before, so the change adds no timing difference between them.FarmClockstays onIAccountRepository. It sits inCluckwork.Infrastructure.Time, which is the Platform hub, and inside the stable account seam. No guard sees it. Switching it would constructFarmModuleand its five handlers on every dated request and buy no check.IAccountRepositoryandDomain.Accountsdirectly. That includes the Close the §4.6 currency-lock race properly (shared lock on the account row across money-writing handlers) #162FOR SHARElocked currency snapshot. The issue body's "lock-aware currency port the Finance pilot introduced" does not exist:CreateExpenseHandler.cs:49callsaccounts.GetCurrentSharedLockedAsync.FarmSettingsDetailsandIFarmModule(same file), because the record carriesDomain.Catalog.EggUnit.SeedDefaults;Domain.AccountsandDomain.Mediavocabulary used inside method bodies;ReportQueries,ExportQueriesandCurrencyBoundRowProbe([C] #514 slice 8: close or date every compatibility exception #850); a contract check for peer modules ([C] #514 slice 7: Finance pilot — first module behind a contract #849 limit).Rationale:
docs/decisions/851-farm-contract.md. AGENTS.md's #849 paragraph now names Farm and links it.Reach
Platform -> Farm)AuthEndpoints.LoginreachThe "before" count comes from running the #849 adapter check on
mainwith a placeholder Farm contract. No edges were added or removed.Change map
Ledger:
Verification
Test baselines, measured, never quoted:
mainb9f7f76main7ce95cf (base)FarmModuleTests)dotnet build Cluckwork.slnis clean with warnings as errors.Security suites, run one by one on this branch, all green. The only test edits in the PR are the two one-line
ResolveFarmCodeAsyncpass-throughs in theIIdentityProviderdecorators inMustChangePasswordGateTestsandStepUpAuthTests.Tenant query-filter and stamping tests are unedited and pass. No entity or mapping changed, so the EF model is identical.
Mutations, each red and then reverted:
IFarmLogoRepository logosadded back toFarmLogoEndpoints.GetLogomakesAdapterReachRealTreeTestsreport a contract bypass.Task<Account?> LeakAsync(CancellationToken ct)onIFarmModulemakesModuleContractRealAssemblyTestsfail.DateFormatOverrideandTimeFormatOverrideinFarmModule's copy makesFarmModuleTestsfail.The first full integration run on this branch had two
SeedCommandTestsdemo-seed cases exceed their 60 s budget while still seeding, at load average 11.8. The demo seeder is untouched. Those 11 tests then passed alone, and a second full run passed 1873/1873.CI
A red
imagecheck is expected and unrelated (#1006).