Aman-Mittal opened a new pull request, #657: URL: https://github.com/apache/fineract-backoffice-ui/pull/657
Adds three real-backend RBAC specs covering authorization dimensions the existing suite cannot reach, and fixes three UI defects those specs surfaced. The existing `rbac-*` specs sign in as users whose roles hold or lack a permission code. That covers the code check and nothing else, so three things went untested: Fineract's office scoping, the gap between authentication and authorization, and what happens when the deployment turns `rbacEnabled` off while the platform keeps enforcing. ## Specs **`rbac-office-scoped-user.spec.ts`** — a user holding `READ_CLIENT` + `READ_OFFICE` in a seeded branch office, **plus a Head Office control user holding the byte-identical role**. Fineract scopes every portfolio query to the office subtree, so two users with the same permission codes see different records and nothing in the code says so. The pair of users is the assertion, because `GET /offices` returns 200 to both — the difference is in the body, not the status. Also asserts that reading another office's client is **404, not 403**: a move to 403 would change what the platform discloses, so it is pinned deliberately. **`rbac-permissionless-user.spec.ts`** — a role granted nothing. Fineract authenticates them (`POST /authentication` → 200, permissions `["FACTOR_PASSWORD"]`) and refuses every portfolio read. The app signs them in and lands them on `/dashboard` rather than stranding them; every gated module is absent from the nav and redirects to `/forbidden` by URL. The part worth having: the entries they are *left* with genuinely work. `/products/share` and `/tellers` answer 200 to anyone signed in because Fineract's catalogue has no READ code for them, so the nav is not a menu of guaranteed failures. **`rbac-disabled-flag-backend.spec.ts`** — `READ_CLIENT` only, with the deployment's `config.json` rewritten to `rbacEnabled: false` (the one stubbed thing; same technique as `oidc-login-backend.spec.ts`). The nav opens up and the guard admits `/accounting/chart-of-accounts` and `/clients/create` — **and Fineract still returns 403** for `/glaccounts`, `/loans`, `/users` and the client POST, while `/clients` stays 200. This makes `security.md` §5a executable instead of prose: the flag changes what is offered, never what is allowed. All three are registered in `BACKEND_SPECS`. `e2e/utils/fineract-login.ts` factors out the seeded-user sign-in that the existing specs each had their own copy of, and `seed-api.ts` gains the ability to place a seeded user in an office other than Head Office. ## UI fixes Each came from watching the live stack, not from reading the code. **1. `client-view` fetches accounts only once the client has loaded.** A branch user opening a head-office client got the page's own "This client doesn't exist, or you don't have permission to view it" *and* a toast reading "The requested resource is not available. • [id] Client not found with valuer 35." The client request already passed `skipErrorToast()` with a comment naming exactly that toast; the accounts request ran beside it, failed identically, and did not skip it — so the suppression had no effect. The accounts are derived from the client, so ordering them removes both the duplicate toast and a request that could never have succeeded. A client that loads and accounts that then fail still toasts, which is the case where the toast is the only feedback. **2. `data-table` tells a refused list from a broken one, and withholds the futile retry.** On Chart of Accounts under `rbacEnabled: false`: "This list could not be loaded." over a "Try again" button that is refused identically on every press — a loop with no exit, over a message that says nothing about what happened. New optional `errorStatus` input; at 403 the table shows `COMMON.ERRORS.LOAD_FORBIDDEN` with a lock icon and no retry. `null` — every call site not updated — is byte-identical to before. Wired at Chart of Accounts and Loans, the two screens where the problem was observed; the remaining call sites are left for the screens that demonstrate the need. **3. `offices-list` gates the edit control on `UPDATE_OFFICE`.** A `READ_OFFICE` user was offered Edit on every row, and `organization/offices/edit/:id` declares `UPDATE_OFFICE` — so the control led straight to Access Denied. The create button beside it has been gated on `CREATE_OFFICE` all along. The spec asserts the hidden control **and** that Fineract answers 403 to the `PUT`, because a test checking only the button would pass against a broken boundary. ## Verification Run against a live Fineract stack after rebasing onto `03533bfc`: ``` npm run lint clean npm run test:unit 278 files, 1822 tests passed npm run build bundle complete npm run i18n:check no missing keys, no phrase labels, catalogues consistent npm run check:template-text no new untranslated template text npm run typecheck:e2e clean check-license.sh all files have headers playwright --project=backend 33 passed (2.3m) — the 3 new specs plus the 2 existing rbac-* specs playwright --project=mocked 209 passed (4.4m) — 13 specs covering every component changed here ``` Also green: `check:route-permissions` (317 screens agree), `check:icons`, `check:a11y-names`, `check:ui-primitives`, `check:nav-ids`, `check:responsive`, `check:internal-endpoints`. **Not verified, stated plainly:** the full 410-test `mocked` project did not complete on `03533bfc` — it was green at `409 passed` on the previous base with all of these changes applied, and the 13-spec targeted subset above is green on `03533bfc`, but the full run was abandoned twice to unrelated machine load. Low risk, but a gap rather than a pass. Not run: `--fresh` (every assertion is scoped to records seeded within the run, and the branch office is created per run, so the office-scope assertions are fresh-safe by construction — but that was not proven on a migration-fresh database), the `two-factor` and `mobile` projects, and `verify-api-client` (nothing generated was touched). ## Open question for reviewers **The Offices screen requests `includeAllOffices=true`**, so a branch user is shown the entire institution's office tree although `GET /offices` alone would have returned their own office. Both calls answer 200 — the client chooses the wider body. This is recorded as an assertion pair and a comment rather than changed, because an office register arguably *should* be institution-wide and that is a product decision, not a bug fix. Happy to follow either way. Two further findings were deliberately left alone: a branch user holding `CREATE_CLIENT` can create a client in Head Office (200) — office scope constrains the reads but not that write, which looks like platform behaviour rather than a UI issue and is not pinned in a spec; and AND semantics (`permissionsMatchAll: true`) exists in the guard but on no route, so testing it would have meant inventing a route. The guard's unit tests already cover those semantics. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
