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]

Reply via email to