Aman-Mittal opened a new pull request, #662:
URL: https://github.com/apache/fineract-backoffice-ui/pull/662

   Follows #660, which fixed the first two instances of this. A static audit of 
controls navigating to a permission-gated route turned up four more, all the 
same shape: **a screen lists records from one domain and links to another, 
where the destination carries a read code the listing itself does not require.**
   
   | Screen | Listing needs | Link goes to | Which needs |
   |---|---|---|---|
   | Client → accounts tabs | `READ_CLIENT` | loan / savings / fixed / 
recurring screens | each account's own read code |
   | Group → members | `READ_GROUP` | `/clients/view/:id` | `READ_CLIENT` |
   | Center → groups | `READ_CENTER` | `/groups/view/:id` | `READ_GROUP` |
   | Asset owner | ungated | `/loans/view/:id` | `READ_LOAN` |
   
   Confirmed against a real instance for the first: a seeded `READ_CLIENT` user 
opened the Loan Accounts tab, clicked the account number, and landed on 
`/forbidden`. The same click as a user who also holds `READ_LOAN` opens the 
loan.
   
   ## The three list screens keep the name, drop the link
   
   The record's existence is not the secret — a group's member list is *for* 
showing membership — and hiding the row would misrepresent the data. So the 
name still renders as plain text; only the link is withheld.
   
   The asset owner screen is different: its control is a header button with no 
record name to preserve, so it is removed outright with `*appHasPermission`, 
which is the documented convention for a control that navigates elsewhere.
   
   ## Why a new helper rather than a directive
   
   Neither structural directive can express this. `*appHasPermission` 
**removes** an element, `appRequiresPermission` **disables** it, and neither 
has an else-branch — but the plain-text fallback is the whole point here.
   
   `createPermissionCheck()` is a factory returning a signal, called as a field 
initializer, matching the existing `createPickersReady()` pattern. It mirrors 
`HasPermissionDirective` including the `rbacEnabled` short-circuit, so a 
deployment that has not adopted RBAC keeps every link. This also replaces the 
private helper `client-view` was carrying from #660, rather than making a 
fourth copy of it.
   
   **This is presentation, not enforcement.** Fineract refuses the read either 
way and remains the authorization boundary — see `security.md`.
   
   ## Coverage
   
   Extends `e2e/rbac-dead-end-controls.spec.ts` with the group member link, 
paired as always with a reader who *does* hold `READ_CLIENT`, because "the link 
is absent" passes just as well against a screen that renders nothing.
   
   `seedGroup` now takes client ids and passes them as `clientMembers` at 
creation, since it previously created groups with no members and the list could 
not be exercised at all.
   
   Both group tests open the Members tab explicitly. **That is worth calling 
out: the first draft passed its negative assertion for the wrong reason** — the 
member was absent because the tab was closed, not because the link was 
withheld. The paired positive test caught it by failing too.
   
   The `asset-owner-view` unit test now covers both states; it previously 
asserted the loan link renders and would otherwise have broken silently in the 
gated direction.
   
   ```
   npx playwright test --project=backend rbac-dead-end-controls.spec.ts
       8 passed (1.0m)
   
   npm run test:unit              279 files, 1827 tests passed
   npm run build                  bundle complete
   npm run lint                   clean
   npm run typecheck:e2e          clean
   npm run check:icons            clean
   npm run i18n:check             clean
   npm run check:template-text    clean
   npm run check:a11y-names       clean
   npm run check:route-permissions  317 screens agree
   npm run check:ui-primitives    clean
   npm run format:check           clean
   scripts/check-license.sh       clean
   ```
   
   ## Not covered by e2e
   
   The center → group link and the asset owner button are covered by the shared 
helper's unit tests and, for the asset owner, its own component test — but not 
by a backend spec. Seeding a center with an associated group is a longer path 
than the value justified here; both go through the same code path as the group 
case that is covered.
   


-- 
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]

Reply via email to