basquetWi + New ticket

Restrict Liquidación report access without changing existing reports

Done high rmresearcher-mba-l-cc

Only /reportes/liquidacion is new; existing reports were already visible to the current Reportes audience. Split Liquidacion authorization from the broad reportes:read permission so its home-page card and route are visible only to explicitly authorized roles/users. Preserve access to pre-existing reports. Add route-level enforcement, not just home-card filtering; document the assigned permission/resource and verify with representative allowed and denied users.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 4w ago
    parent=#3410
  • wi-cli-venus assigned · 4w ago
    coder02-mba-l-ca / coder
  • wi-cli-venus assigned · 4w ago
    coder03-mba-l-cc / coder
  • coder03-mba-l-cc assigned · 2w ago
    coder04-mba-l-ca
  • coder03-mba-l-cc assigned · 1w ago
    researcher-mba-l-cc / solo
  • researcher-mba-l-cc statusChanged · 1w ago
    Researcher started at 2026-10-08T12:02:24-03:00.
  • researcher-mba-l-cc spec · 1w ago
    researcher-mba-l-cc CURRENT STATE (confirmed by code, matches the ticket's framing exactly): Liquidacion has NO resource of its own. All three enforcement points share the same broad "reportes" RBAC resource as every pre-existing report: 1. src/app/reportes/page.tsx:40 - home-card visibility gate: `canRead("reportes")`, same check as the page-level entry gate at line 16 (so it's trivially true for anyone who got past the page gate at all - the card check is currently a no-op). 2. src/app/reportes/liquidacion/page.tsx:67,117 - client-side page gate: `canPerformAction("reportes", "read")`. 3. src/actions/reportes.ts:21 - the SERVER ACTION's own authorization check inside getLiquidacionMensual: `hasPermission(userId, "reportes", "read")`. This is the one that matters most - it's already route-level in the sense that hiding the card doesn't block a direct call, but it still answers to the wrong (too-broad) resource. RBAC MODEL (src/lib/rbac.ts, DB-backed, tables already exist - `resources`, `permissions`, `groups_permissions`, `groups`, `users_groups`): resources are rows, not code constants. Adding a new resource is a DATA insert against an existing table, not a schema/DDL change. FIX - new resource `reportes-liquidacion`, three code changes + one data change: 1. DATA (db lane, SELECT-only constraint means I cannot do this myself): insert a `resources` row named `reportes-liquidacion`, then grant it `read` via `groups_permissions` to whichever groups/users should keep Liquidacion access. This is the step that actually restricts access - everyone currently seeing Liquidacion today rides the generic `reportes` grant, so until this insert + explicit re-grant happens, NO ONE has `reportes-liquidacion` and the card/route disappears for everyone, including users who should keep it. Elazar names which roles/users keep access before this ships - that's a decision, not something to infer from current "reportes" holders (the ticket's whole point is that the current audience is too broad). 2. src/app/reportes/page.tsx:40 - change the liquidacion card's gate from `canRead("reportes")` to `canRead("reportes-liquidacion")`. Leave the page-level gate at line 16 and the other two cards' `canRead("vehiculos")` untouched - this preserves access to pre-existing reports exactly as the ticket requires. 3. src/app/reportes/liquidacion/page.tsx:67,117 - same resource swap, `canPerformAction("reportes-liquidacion", "read")`. 4. src/actions/reportes.ts:21 - same swap inside `puedeVerReportes` (or whatever the local helper is named) - `hasPermission(userId, "reportes-liquidacion", "read")`. This is the actual route-level enforcement the ticket asks for: even a user who still has the page visible some other way (stale client bundle, direct POST) gets rejected by the server action itself. VERIFICATION (per ticket's own ask - representative allowed/denied users, not just the home card): - Denied user: has `reportes` but not `reportes-liquidacion` - confirm (a) no Liquidacion card on /reportes, (b) direct navigation to /reportes/liquidacion renders but getLiquidacionMensual returns the "Sin permisos" error (client gate at line 117 also blocks render, so confirm BOTH layers independently - client gate alone is not the control, per Elazar's own auth-gate guardrail), (c) the OTHER cards (rutap-history, fleet, vehicle-pdf) still show - this is the "preserve existing access" check. - Allowed user: has both `reportes` and `reportes-liquidacion` - confirm the card shows and the report generates end to end. - This needs a db-lane write (the resource insert + grants) before any of it is testable - sequence this after db applies step 1, not before. SCOPE NOT TOUCHED: the other two report cards and their `vehiculos`/`reportes` gates stay exactly as they are - nothing here changes what anyone with plain `reportes` or `vehiculos` can already see.
  • coder03-mba-l-cc completed · 1w ago
    Elazar decision 2026-10-08 12:46 ART (CLI, nqla 4b): Liquidacion stays under the broad 'reportes' RBAC resource until go-live; revisit when a grant UI exists. No code change.
bug
4w ago by wi-cli-venus
1w ago
2026-10-08 15:17