Lewati ke isi

T6B Authorization Traceability (SC-FEES / W10)

Historical T6B-B status: source inventory only. Not a certified authorization matrix. Product gate FAIL; no live negative cases executed.

Historical identity: FE tree 8362e7db… · BE tree a31fe594… · BE api_route_access.py SHA-256 72b1d590… · FE registry SHA-256 4688c5e6…

T6B.1 identity: FE app 2f716594ee76… / tree 8606e7bb… · BE e78d06d1ff64… / tree 6d13752c… · BE registry SHA-256 269b4abd1f191d5abf27dd818d741557671437aa500675d080b316e9acd50ca9 · FE registry SHA-256 fd24a9c5058312891051409c60693face482fc9ba5bd6d927ab0420ac7738722

Invariants that already exist (must not be weakened)

  • Entitlement is additive to capability (DEC-003). Installed ≠ entitled.
  • Viewer must not mutate.
  • GT-T1 must not read/write GT-T2.
  • Direct /web/dataset / call_kw / call_button must fail-closed for Fees models.
  • Parent-child and student self-scope are mandatory once a contract exists.
  • scola_fees sudo budget is 21/21. Do not raise MODULE_BUDGETS without written cause.

Capability vocabulary (current)

From auth_capabilities.py:

  • finance.billing.view
  • finance.billing.manage
  • finance.billing.receive_cash
  • finance.billing.verify
  • finance.payment.manage
  • finance.payment.setup
  • finance.fees.view

Plus FE-only names used in financeApp.js: finance.fee_templates.view, finance.scholarships.view, finance.installments.view, finance.spp_by_class.view.

Entitlement prefixes in platform_entitlements.py: finance.billing.*, finance.fees.*, finance.payment.* → flag scola_fees.

Registry vs controller gaps

Surface Registry capability Controller gate Elevation Tenant/student predicate Entitlement Finding
Prefix /api/v1/finance/ finance.billing.view various mixed sudo incomplete scola_fees DEC-003 collapse: unmatched finance paths are view
Prefix /api/v1/payment/ finance.payment.manage mixed mixed incomplete scola_fees public callbacks are separate paths
Prefix /api/fees/ finance.billing.view fees_api.py unknown unknown scola_fees broad prefix
POST /api/v1/finance/fee-enrollments/save prefix view _can_manage Enrollment.sudo() browse(id) then write(values); no company assert flag STAB-014; client amount write possible
POST /api/v1/finance/fee-enrollments/delete prefix view _can_manage sudo browse then unlink flag STAB-014
POST /api/v1/finance/fee-enrollments/action prefix view _can_manage sudo browse then approve/draft flag no SoD
POST /api/v1/finance/fee-enrollments/lookups view _can_view op.student.sudo().search no company unscoped student/course flag tenant leak vector
/api/v1/finance/accounting/invoices/bulk-create finance.billing.manage accounting controller account.payment.register later invoice company? scola_fees not scola_account accounting mutation inside Fees
/api/v1/finance/accounting/invoices/approve manage writes admin_state sudo journals unsigned Fees posting-adjacent
/api/v1/finance/accounting/payments/submit manage account.payment.register.sudo() sudo unsigned Fees journal path uncertified
/api/v1/payment/manual/create + proof/submit/verify/reject/cash payment.manage manual_payment_api mixed invoice_id Fees states pending/verified/rejected only
POST /payment/callback/midtrans public gateway n/a unsigned signature/replay public enumeration/replay risk
POST /payment/callback/xendit public gateway n/a unsigned public same
GET /api/v1/payment/status/<id> payment.manage prefix gateway n/a transaction id Fees enumeration if IDOR
/api/v1/parent/billing /parent/invoices/<id> parent parent_billing_api mixed child link unproven live Fees+parent bridge bridge uninstalled on current mixed DBs
Native /web/dataset on fee/invoice/payment models Odoo ACL none canonical native native n/a not proven fail-closed

.sudo() / superuser browse (Fees controllers)

Observed (not exhaustive of models/wizards):

  • fee_enrollment_api.py: enrollment env sudo; template sudo; unscoped op.student / op.course / op.batch sudo; bulk/generate wizards sudo; schedule sudo search
  • finance_fee_api.py: template sudo; generate wizard sudo; course/batch/student/product sudo with allowed_company_ids on some paths
  • payment_accounting_api.py: account.payment.register.sudo(); account.journal.sudo().name_search; payment method lines sudo
  • payment_catalog_api.py: generic model sudo with company context

STAB-014 cites fee_enrollment_api.py:135-175,180-235,263-267 as missing explicit tenant ownership on elevated IDs/FKs. Independent read of current source confirms the save/delete/action/lookup pattern is still present.

Actor hypotheses (unsigned — do not implement as policy)

Catalog proposes school_admin, treasurer, head_admin/admin_staff/vice_principal_finance, student/parent self-scope. vp-finance shell is Requires Product Decision. admin-staff is mixed without package owner.

Until the 30-property contract is signed, this table is not a role binding.

What was not executed

  • Live viewer-mutate, parent IDOR, student IDOR, teacher billing, GT-T1/T2
  • /web/dataset create/write/unlink on Fees models
  • Installed-but-unentitled API on disposable DB
  • Public callback replay
  • Maker-checker self-approval

Those belong to PKG-FEES-W10 after a signed contract.


T6B.1 descendant (engineering matrix, not independent certification)

Invariants above were not weakened. scola_fees sudo is 15/21.

Canonical W10 capabilities

  • finance.billing.view
  • finance.billing.configure
  • finance.billing.receive_cash
  • finance.billing.verify
  • finance.billing.refund
  • finance.billing.manage
  • finance.billing.self.view
  • finance.billing.self.pay

Registry v11 exact /api/v1/fees/w10/* rows win over /api/v1/finance/ prefix. Exact /api/v1/payment/create is receive_cash and returns gateway_excluded.

Live negative proof (overlay)

Surface Proof
Viewer mutate RT-W10-NEG-01 capability_denied on rules/save
Cashier cannot verify POS self-verify denied; STA SoD
Parent/student guessed ID SCP + NEG not_found without existence leak
GT-T1/T2 RT-W10-TEN-01
Package OFF RT-W10-UIA-01 feature_disabled
Gateway/journal/legacy enroll RT-W10-XMD-01 fail-closed
/web/dataset still native ACL; not a W10 alternate lifecycle (contract item 30)

FE/BE drift that remains: treasurer FE finance.payment.setup/manage; head_admin FE extra finance.billing.manage. See residuals T6B-R002/R003.