Aman-Mittal opened a new issue, #696:
URL: https://github.com/apache/fineract-backoffice-ui/issues/696
Separate from #691, which is about a dispatch route declaring one code for
many commands. These are individual gates naming the wrong code, or a code that
does not exist at all.
Each was measured against a running Fineract with an **empty body**, which
separates authorisation from validation without writing anything: the platform
authorises before it validates, so `403 error.msg.not.authorized` means the
code is wrong and `400 validation.msg...` means it is right and only the body
was bad.
## 1. The savings cash-withdrawal button asks for the application-withdrawal
code
`savings-account-view.component.ts`:
```html
<ion-button data-testid="savings-withdraw-action"
appRequiresPermission="WITHDRAW_SAVINGSACCOUNT"
(click)="onTransaction('withdrawal')">
```
Both codes exist, one letter apart, and they are strictly
non-interchangeable:
| Operation | `WITHDRAWAL_SAVINGSACCOUNT` | `WITHDRAW_SAVINGSACCOUNT` |
| --- | --- | --- |
| cash withdrawal (`transactions?command=withdrawal`) | **400 authorised** |
403 refused |
| application withdrawal (`?command=withdrawnByApplicant`) | 403 refused |
**400 authorised** |
`WITHDRAW_SAVINGSACCOUNT` withdraws the *application* — which is what the
Withdrawn-by-applicant button immediately above it correctly uses. This one
withdraws *cash*.
So a teller holding `WITHDRAWAL_SAVINGSACCOUNT` is shown a disabled Withdraw
button they are entitled to use, and a holder of the application code is
offered an enabled one the platform refuses.
This is the one a static check cannot find, because both codes are real.
## 2. `UNDOWITHDRAW_CLIENT` does not exist
`client-view.component.ts` gates the client undo-withdrawal action on it.
The real code is `UNDOWITHDRAWAL_CLIENT` — the same missing "AL" as above:
```
POST /clients/{id}?command=undoWithdrawal
UNDOWITHDRAWAL_CLIENT → 400 authorised
WITHDRAW_CLIENT → 403 refused
```
## 3. `UPDATE_LOAN_AVAILABLE_DISBURSEMENT_AMOUNT` does not exist, and
nothing can replace it
`loan-view.component.ts` gates the revise-available-disbursement-amount
action on it. There is no such code — and no narrower one, either. Found by
bisecting the whole catalogue:
- a role granted **all 721 grantable codes** is still refused `PUT
/loans/{id}/available-disbursement-amount` with 403;
- the superuser gets 400 on the identical request.
So the endpoint is genuinely superuser-only. `ALL_FUNCTIONS` is the honest
declaration, and it makes the refusal hint name something an administrator can
act on.
Arguably the platform should define a grantable code for an operation it
exposes; that belongs in the [ASF Jira
project](https://issues.apache.org/jira/projects/FINERACT) rather than here,
and is noted only because it is why this one cannot be fixed by naming a better
code.
## 4. Office transactions — and #665's proposed fix would not have worked
Recorded here because measuring it changed the answer. #665 recommended
requiring `READ_OFFICETRANSACTION` **and** `READ_OFFICE`. In fact the
transaction code does nothing for these endpoints at all:
```
READ_OFFICE alone → GET /officetransactions 200,
/officetransactions/template 200
READ_OFFICETRANSACTION alone → 403, 403
READ_CLIENT alone (control) → 403, 403
```
An AND would still refuse a `READ_OFFICE` holder the platform serves.
## Why 2 and 3 are the worst of these
`DOCS/RBAC.md` already says it:
> **Do not invent codes.** A gate on a code that does not exist can never be
satisfied by any role, which is worse than no gate.
A control gated on a nonexistent code is disabled *forever*, for every
account except a superuser's, and looks exactly like a control the viewer is
not entitled to. Nobody reports it, because the UI is behaving as though the
answer were "no".
## Fix
#695, along with a check so the class cannot return.
`scripts/check-permission-codes.mjs` compares every code named in an action
gate, structural gate, route, nav entry, data table or command map against a
committed snapshot of the catalogue — 311 codes today — and runs in CI with no
Fineract started. Its header states plainly what it **cannot** catch, which is
defect 1: a code that exists but is wrong for the operation. That needs a run
against a real platform, which `e2e/savings-flows-non-admin-roles.spec.ts` now
provides, asserting the withdrawal code from both sides.
How 2 and 3 were found is worth noting: not by using the app, but by diffing
the source against a live `GET /v1/permissions`. Neither would have surfaced
from a bug report.
--
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]