Lewati ke isi

T0-E1.2 — Authority Callsite Audit (gcgscola production Python)

Item Value
Mode Server /home/scola/odoo
Workspace root /home/scola/odoo
Docs read workspace-governance.md, T0-E1.1-result.md, T0-E1.2-preflight.md
Scope custom_addons_scola/gcgscola — controllers / services / models (skip tests, scripts, migrations unless production-capable)
Thoroughness medium
BE HEAD scanned d947ed9 (main)
FE docs repo 7ca45c6c (develop) — docs only; Python not modified
Prior control E1.1 unified AuthorityContext + compute_permissions active-role-only (no preferred/group widen for capabilities)

Method

Inventory patterns (production paths only):

  1. has_group('scola_core...
  2. resolve_role_id(
  3. user.scola_role used for authorization (not display/serialize)
  4. _user_has_scola_product_authority
  5. compute_permissions( without explicit active_role= / session=
  6. Preferred-role / group fallbacks used for authz

Classification legend:

Class Meaning
FRAMEWORK_ELIGIBILITY_ONLY Decides whether a gate applies to a Scola actor; does not grant product caps by inactive role
DEFAULT_ROLE_SELECTION_ONLY Login / preferred / display default; not request capability axis
DISPLAY_ONLY Payload / UI labels
AUTHORIZATION Grants or denies API/model action
TENANT_SCOPE Widens/narrows company set
RECORD_SCOPE Widens/narrows which records are visible/mutable
LEGACY_DEAD Unreachable or superseded path

Recommended E1.2 action: KEEP | ROUTE_THROUGH_AUTHORITY | REMOVE | NARROW.

Risk after E1.1: HIGH = still grants admin/school-wide power via group or preferred role while active role may be narrower; MED = wrong role axis / union of assigned roles / group OR preferred without session; LOW = session-aware or eligibility/display.


Inventory summary (production)

Pattern Approx. production sites Notes
has_group('scola_core…') ~70 hits / 33 files Dense in CBT, portal notification admin, student_activity models
resolve_role_id( 3 call clusters Defn in auth_capabilities; callers: auth.py, core_reference_api audit log
_user_has_scola_product_authority 1 def + 2 uses ir_http dataset / product web gate
compute_permissions(user=…) w/o explicit session ~25 controllers + 1 model After E1.1 helper auto-reads request.session → active role; residual risk mainly non-HTTP callers
user.scola_role authz ~12 controllers/models Dashboard access + finance role unions + news audience
Preferred/group fallback helpers resolve_role_id, SubscriptionWorkflowMixin._resolve_role, several _role_codes Still OR preferred + groups

Already aligned (brief — not HIGH/MED residual)

  • authority_context.build_authority_context / get_request_authority — session active role only.
  • compute_permissions body — no preferred/resolve_role_id fallback (E1.1).
  • company_scope.resolve_user_company_ids / foundation expand — active role only.
  • teacher_scope.requires_teacher_student_scope — active role; faculty groups only narrow, never widen school-wide.
  • Controllers using CoreApiController._scola_role() / get_request_authority for gates (LMS, fees finance config, leadership hub, identity_admin primary checks, etc.).

HIGH / MED residual sites

A. Direct group_scola_admin (and peers) for AUTHORIZATION — can widen beyond active role

file:line Snippet Class Residual after E1.1 E1.2 action
scola_portal/controllers/calendar_admin_api.py:28 _can_manage_calendar: active role OR has_group('…group_scola_admin') AUTHORIZATION HIGH — admin group grants calendar admin while acting as teacher ROUTE_THROUGH_AUTHORITY (drop group OR; keep active-role set)
scola_report_card/controllers/report_card_api.py:56-62 _is_admin_user: scola_is_admin OR group_scola_admin AUTHORIZATION HIGH — persistent flag/group bypasses active role ROUTE_THROUGH_AUTHORITY
scola_report_card/controllers/learning_outcome_admin_api.py:62-65 scola_role in allowed OR group_scola_admin OR report_card manager OR base.group_system AUTHORIZATION HIGH — preferred role + admin group widen ROUTE_THROUGH_AUTHORITY
scola_student_activity/controllers/violation_admin_api.py:65-67 _has_violation_master_manage_access: group_scola_admin OR activity manager AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_student_activity/models/violation_log.py:268 manage check via group_scola_admin AUTHORIZATION / RECORD_SCOPE HIGH ROUTE_THROUGH_AUTHORITY
scola_student_activity/models/achievement.py:237 same pattern AUTHORIZATION / RECORD_SCOPE HIGH ROUTE_THROUGH_AUTHORITY
scola_student_activity/models/student_permit.py:163,173,241 approve / group access: admin group short-circuit AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_core/models/academic_term.py:51 action_unlock requires group_scola_admin AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_lms/models/ir_attachment.py:98-99 _check_lms_material_manage_access admin group (duplicated OR) AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_lms/models/op_teaching_assignment.py:516 calendar domain: if not admin group → empty; else school-wide RECORD_SCOPE HIGH — admin group ⇒ unscoped assignment feed ROUTE_THROUGH_AUTHORITY / NARROW
scola_cbt/controllers/exam.py:472,482 Access Denied unless faculty-like OR CBT groups OR group_scola_admin AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_cbt/controllers/participant.py:94,104 same admin-group OR AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_cbt/controllers/report.py:46,118,143 report access: system OR admin OR CBT manager (+ principal / wakasek) AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_cbt/controllers/grading.py:119 grading gate includes group_scola_admin AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_cbt/models/exam.py:700 model gate: system OR admin OR CBT manager AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_portal/controllers/portal_api.py:586,630,671,695,736,755 notification / WA / Telegram config: portal admin OR system OR group_scola_admin AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY (prefer capability/notification_config_api authority path)
scola_hr_attendance/controllers/hr_attendance_checkin_api.py:521 _can_proxy_hr_attendance: HR manager OR group_scola_admin OR system AUTHORIZATION HIGH — proxy punch for others ROUTE_THROUGH_AUTHORITY
scola_core/controllers/admin_import_api.py:30-33 scola_is_admin OR user-management authority group AUTHORIZATION HIGH ROUTE_THROUGH_AUTHORITY
scola_core/models/student_import_job.py:84 same scola_is_admin pattern AUTHORIZATION MED→HIGH ROUTE_THROUGH_AUTHORITY

B. Preferred scola_role / assigned-role union for AUTHORIZATION

file:line Snippet Class Residual after E1.1 E1.2 action
scola_bos_rkas_executive_bridge/controller_support.py:13-16 user.scola_role in principal set OR group_scola_principal AUTHORIZATION MED — preferred/group, not session ROUTE_THROUGH_AUTHORITY
scola_account/controllers/bendahara_dashboard_api.py:20-24 treasurer group OR scola_role == treasurer OR group name string AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY
scola_account/controllers/principal_finance_api.py:20-24 principal / wakasek finance / account manager groups only AUTHORIZATION MED — inactive group while acting teacher ROUTE_THROUGH_AUTHORITY
scola_library/controllers/librarian_dashboard_api.py:29 OpenEduCat/library groups OR scola_role in librarian AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY
scola_library/controllers/library_canonical_ops_api.py:43 library groups OR group_scola_principal OR system AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY
scola_counseling/controllers/counselor_dashboard_api.py:32 counseling groups OR scola_role in counselor… AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY
scola_inventory/controllers/laboran_dashboard_api.py:23 scola_role == lab_technician OR group name AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY
scola_fees/controllers/manual_payment_api.py:40-51 _role_codes: preferred + all scola_roles M2M → finance/kasir AUTHORIZATION / RECORD_SCOPE HIGH — union of assigned roles ignores active role NARROW to active role (+ capability)
scola_fees/controllers/finance_spp_report_api.py:56-104 _role_codes / _can_access / _is_homeroom_scope: preferred + M2M + homeroom group; dual-role widen when preferred teacher AUTHORIZATION / RECORD_SCOPE HIGH ROUTE_THROUGH_AUTHORITY + NARROW
scola_fees/controllers/payment_gateway_api.py / payment_setup_api.py same _role_codes style (M2M union) AUTHORIZATION MED→HIGH NARROW
scola_platform_support/subscription_workflow.py:55-73 _resolve_role: preferred scola_role then group map (platform_operator / head_admin / principal) AUTHORIZATION MED — platform/tenant subscription gates ROUTE_THROUGH_AUTHORITY
scola_cbt/controllers/exam.py:22-31 (+ question/participant/question_set) faculty-like via teacher/homeroom groups + preferred/scola_roles codes AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY
scola_hr_attendance/controllers/hr_attendance_reports_api.py:680,726 lock period: HR manager OR principal OR foundation_hr_admin groups AUTHORIZATION MED ROUTE_THROUGH_AUTHORITY

C. RECORD_SCOPE / TENANT_SCOPE via group or preferred role

file:line Snippet Class Residual after E1.1 E1.2 action
scola_lms/models/op_teaching_assignment.py:461-516 domain by student/parent/faculty groups; admin group = no teacher narrow RECORD_SCOPE HIGH (admin branch); MED (student/parent via group while other active role) NARROW / ROUTE_THROUGH_AUTHORITY
scola_counseling/controllers/counseling_portal_api.py:92,142 student group → self-domain RECORD_SCOPE MED NARROW to active student / identity
scola_cbt/controllers/student_schedule.py:34 student group → own student ids RECORD_SCOPE MED NARROW
scola_core/services/academic_calendar_scope.py:137,195 scola_role(user) OR student group for viewer students/levels RECORD_SCOPE MEDscola_role() is preferred helper ROUTE_THROUGH_AUTHORITY / use _active_role_code
scola_core/models/ir_attachment.py:13 student group → attachment create for own submission RECORD_SCOPE LOW–MED (create only; identity-bound) KEEP or NARROW
scola_news/models/scola_news.py:714,729 _user_is_parent/_student: preferred role OR groups OR identity search RECORD_SCOPE MED NARROW to identity + active role
scola_student_activity/models/student_permit.py:192 _is_student_permit_user via student group RECORD_SCOPE MED NARROW

D. Framework / default-role / resolve_role_id (not product cap axis, but residual callers)

file:line Snippet Class Residual after E1.1 E1.2 action
scola_core/services/auth_capabilities.py:829-855 resolve_role_id: preferred then group_scola_adminschool_admin, system→admin, GROUP_ROLE_MAP DEFAULT_ROLE_SELECTION_ONLY LOW if callers stay display/login; MED if reused for authz KEEP for login default; ban from authz (NARROW docs/guards)
scola_core/controllers/auth.py:122,187 _get_role_id / _build_auth_payload: active_role or resolve_role_id(user) DEFAULT_ROLE_SELECTION_ONLY (+ payload role) MED — empty session role falls back to preferred/group (can surface school_admin in payload) NARROW: fail-closed empty active role; never group-widen payload caps (caps already session-scoped via compute_permissions)
scola_core/controllers/core_reference_api.py:91 audit log field uses resolve_role_id(user) labeled active_role DISPLAY_ONLY (mislabel) LOW — logging only NARROW label → preferred/resolved
scola_core/models/ir_http.py:148-151 session_info: role = active or user.scola_role; preferred_role; is_admin = scola_is_admin DISPLAY_ONLY / FRAMEWORK LOW–MED — FE may trust role/is_admin NARROW display contract
scola_core/models/ir_http.py:268-297 _user_has_scola_product_authority: scola_role OR scola_roles OR product groups FRAMEWORK_ELIGIBILITY_ONLY LOW for T0F-001 widen; eligibility for dataset deny KEEP (do not use for product caps)
scola_core/utils/teacher_scope.py:64-68 faculty groups → require teacher scope (narrow) RECORD_SCOPE (narrowing) LOW — intentional fail-closed narrow KEEP
scola_attendance/controllers/attendance_api_mixin.py:1587 pickup officer group check on driver user AUTHORIZATION (device eligibility) LOW–MED KEEP / review if dual-role

E. compute_permissions(user=…) without explicit session

Post-E1.1, compute_permissions resolves request.session when active_role omitted. Call sites are LOW residual on HTTP request path; list for hygiene:

admission_config_api, privacy_api, security_visitor_api, committee_dashboard_api, foundation_auditor_dashboard_api, faculty_admin_api, violation_admin_api, kesiswaan_*, counseling_domain_api, fee_enrollment_api, accounting_*, budget_admin_api, procurement_admin_api, payslip_admin_api, payroll_config_api, hr_admin_api, employee_admin_api, hr_attendance_admin_api, inventory_admin_api, student_face_admin_api, debug_access_api, lms_weekly_approval_api, weekly_teacher_report (model).

Class Residual E1.2 action
AUTHORIZATION (capability set) LOW on /api with session; MED if invoked from cron/shell/model without session → empty caps (fail-closed) or stale scola_effective_permissions on privacy Prefer get_request_authority().capabilities / pass session= explicitly (ROUTE_THROUGH_AUTHORITY)

Short summary — sites that can still widen school_admin beyond active role

Setelah E1.1, capability matrix (compute_permissions / registry capability gate) sudah session-active-role-only. Residual widen ke kekuasaan setara school_admin / admin masih terjadi di jalur yang bypass authority dan membaca group / flag / preferred role:

  1. has_group('scola_core.group_scola_admin') short-circuit — calendar admin, report card admin, learning outcome admin, violation/achievement/permit models, academic term unlock, LMS attachment + assignment calendar scope, CBT exam/participant/report/grading/model, portal notification config (6 call sites), HR attendance proxy punch.
  2. scola_is_admin flag — report_card _is_admin_user, admin import / student import job (dan finance SPP role codes treating scola_is_admin as admin).
  3. Assigned-role union — fees _role_codes (manual payment / SPP report / payment setup): preferred + full scola_roles M2M grants finance/admin-like access without acting as that role.
  4. resolve_role_id / auth payload fallback — tidak lagi mengisi capabilities, tetapi masih bisa menampilkan / memilih default school_admin dari group jika session active role kosong (auth.py).

Tidak lagi (setelah E1.1) jalur utama: inactive platform_operator group → widen school_admin lewat compute_permissions (T0F-001 fixed on capability path). Residual adalah callsite lokal yang belum diarahkan ke AuthorityContext.

Suggested E1.2 priority (implementation later; this doc is audit-only)

  1. Strip group_scola_admin / scola_is_admin OR-branches on mutation & school-wide reads (calendar, portal notify, CBT, student_activity, academic_term, LMS).
  2. Replace fees/dashboard _role_codes / preferred-role checks with get_request_authority().active_role_in(...) / has_capability(...).
  3. Keep resolve_role_id + _user_has_scola_product_authority as eligibility/default only; add lint/tests forbidding new authz use.

Explicit non-claims

  • Does not claim T0 CLOSED / independent audit pass.
  • Does not modify Python.
  • Medium thoroughness: clustered CBT/portal duplicates; optional packages with identical patterns noted by representative sites. )