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_buttonmust fail-closed for Fees models. - Parent-child and student self-scope are mandatory once a contract exists.
scola_feessudo budget is 21/21. Do not raiseMODULE_BUDGETSwithout written cause.
Capability vocabulary (current)¶
From auth_capabilities.py:
finance.billing.viewfinance.billing.managefinance.billing.receive_cashfinance.billing.verifyfinance.payment.managefinance.payment.setupfinance.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; unscopedop.student/op.course/op.batchsudo; bulk/generate wizards sudo; schedule sudo searchfinance_fee_api.py: template sudo; generate wizard sudo; course/batch/student/product sudo withallowed_company_idson some pathspayment_accounting_api.py:account.payment.register.sudo();account.journal.sudo().name_search; payment method lines sudopayment_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/datasetcreate/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.viewfinance.billing.configurefinance.billing.receive_cashfinance.billing.verifyfinance.billing.refundfinance.billing.managefinance.billing.self.viewfinance.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.