From 1b74af4d3a0c35f09dcac1ddb6c0fa6b41adeaca Mon Sep 17 00:00:00 2001 From: tyler Date: Wed, 24 Jun 2026 17:58:31 -0600 Subject: [PATCH] fix(permissions): populate matrix for all gated endpoints The matrix_gate dependency was added to ~50 routes (clearhouse, all /api/admin/*, /api/config/*, /api/eligibility/*, /api/parse-999/ta1/277ca, /api/batches/{id}/export-837, /api/payer-rejected/acknowledge, etc.) but the PERMISSIONS matrix was only populated for ~25 of them. Default- deny therefore returned 403 to every authenticated role on the rest, including the SFTP admin endpoints needed for MFT polling. Roles: - Admin-only: /api/clearhouse* (SFTP creds + dzinesco identity), all /api/admin/* (audit-log, backup, scheduler, db rotate, reload-config, validate-provider) - All authenticated: /api/batch-diff, /api/config/*, /api/payers/* - Write (admin + user, no viewer): /api/parse-999/ta1/277ca, the /api/batches POST prefix (regenerates X12 from DB rows), and /api/eligibility/* (270 build / 271 parse) Unblocks /api/clearhouse, /api/admin/scheduler/*, /api/admin/backup/*, and the rest of the admin surface so MFT polling and live verification can proceed. --- backend/src/cyclone/auth/permissions.py | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/backend/src/cyclone/auth/permissions.py b/backend/src/cyclone/auth/permissions.py index 8a9a13c..917e3f3 100644 --- a/backend/src/cyclone/auth/permissions.py +++ b/backend/src/cyclone/auth/permissions.py @@ -47,11 +47,35 @@ PERMISSIONS: dict[tuple[str, str], set[Role]] = { ("GET", "/api/acks"): ALL_ROLES, ("GET", "/api/ta1-acks"): ALL_ROLES, ("GET", "/api/277ca-acks"): ALL_ROLES, + ("GET", "/api/batch-diff"): ALL_ROLES, + ("GET", "/api/config"): ALL_ROLES, + ("GET", "/api/payers"): ALL_ROLES, ("GET", "/api/audit-log"): ADMIN_ONLY, + # Clearhouse (SFTP creds + dzinesco identity) — admin only. + ("GET", "/api/clearhouse"): ADMIN_ONLY, + ("PATCH", "/api/clearhouse"): ADMIN_ONLY, + ("POST", "/api/clearhouse/submit"): ADMIN_ONLY, + + # Admin ops (audit log, backup, scheduler, db rotate, reload-config). + ("GET", "/api/admin/audit-log"): ADMIN_ONLY, + ("GET", "/api/admin/audit-log/verify"): ADMIN_ONLY, + ("GET", "/api/admin/backup"): ADMIN_ONLY, + ("POST", "/api/admin/backup"): ADMIN_ONLY, + ("GET", "/api/admin/backup/scheduler"): ADMIN_ONLY, + ("POST", "/api/admin/backup/scheduler"): ADMIN_ONLY, + ("GET", "/api/admin/scheduler"): ADMIN_ONLY, + ("POST", "/api/admin/scheduler"): ADMIN_ONLY, + ("POST", "/api/admin/db/rotate-key"): ADMIN_ONLY, + ("POST", "/api/admin/reload-config"): ADMIN_ONLY, + ("GET", "/api/admin/validate-provider"): ADMIN_ONLY, + # Write endpoints (admin + user, no viewer). ("POST", "/api/parse-837"): WRITE_ROLES, ("POST", "/api/parse-835"): WRITE_ROLES, + ("POST", "/api/parse-999"): WRITE_ROLES, + ("POST", "/api/parse-ta1"): WRITE_ROLES, + ("POST", "/api/parse-277ca"): WRITE_ROLES, ("POST", "/api/inbox"): WRITE_ROLES, ("POST", "/api/inbox/candidates"): WRITE_ROLES, ("POST", "/api/inbox/rejected"): WRITE_ROLES, @@ -60,6 +84,8 @@ PERMISSIONS: dict[tuple[str, str], set[Role]] = { ("POST", "/api/reconciliation"): WRITE_ROLES, ("POST", "/api/resubmit"): WRITE_ROLES, ("POST", "/api/acks"): WRITE_ROLES, + ("POST", "/api/batches"): WRITE_ROLES, # /export-837 regenerates X12 from DB rows + ("POST", "/api/eligibility"): WRITE_ROLES, # CSV export — read-only. ("GET", "/api/export.csv"): ALL_ROLES,