@jmruthers/pace-core 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +104 -0
- package/README.md +5 -403
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-pace-core-compliance.mdc +128 -26
- package/cursor-rules/01-standards-compliance.mdc +49 -8
- package/cursor-rules/02-project-structure.mdc +6 -0
- package/cursor-rules/03-solid-principles.mdc +2 -0
- package/cursor-rules/04-testing-standards.mdc +2 -0
- package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
- package/cursor-rules/06-code-quality.mdc +2 -0
- package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
- package/cursor-rules/08-markup-quality.mdc +52 -27
- package/cursor-rules/09-rbac-compliance.mdc +462 -0
- package/cursor-rules/10-error-handling-patterns.mdc +179 -0
- package/cursor-rules/11-performance-optimization.mdc +169 -0
- package/cursor-rules/12-ci-cd-integration.mdc +150 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
- package/dist/DataTable-LRJL4IRV.js +15 -0
- package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
- package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
- package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/chunk-4T7OBVTU.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
- package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
- package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
- package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/chunk-OHIK3MIO.js +994 -0
- package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
- package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
- package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
- package/dist/components.d.ts +6 -6
- package/dist/components.js +57 -267
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +22 -0
- package/dist/eslint-rules/rules/compliance.cjs +348 -0
- package/dist/eslint-rules/rules/components.cjs +113 -0
- package/dist/eslint-rules/rules/imports.cjs +102 -0
- package/dist/eslint-rules/rules/rbac.cjs +790 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +62 -270
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +36 -26
- package/dist/index.js +87 -690
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +124 -594
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +16 -6
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +454 -930
- package/docs/api-reference/components.md +3 -1
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/best-practices/accessibility.md +6 -3
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/permission-enforcement.md +4 -0
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +12 -3
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/secure-client-protection.md +0 -34
- package/docs/standards/00-pace-core-compliance.md +967 -0
- package/docs/standards/01-standards-compliance.md +188 -0
- package/docs/standards/02-project-structure.md +985 -0
- package/docs/standards/03-solid-principles.md +39 -0
- package/docs/standards/04-testing-standards.md +36 -0
- package/docs/standards/05-bug-reports-and-features.md +27 -0
- package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
- package/docs/standards/07-tech-stack-compliance.md +30 -0
- package/docs/standards/08-markup-quality.md +345 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
- package/docs/standards/10-error-handling-patterns.md +401 -0
- package/docs/standards/11-performance-optimization.md +348 -0
- package/docs/standards/12-ci-cd-integration.md +370 -0
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
- package/docs/standards/README.md +62 -33
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +20 -4
- package/package.json +31 -21
- package/scripts/audit/audit-compliance.cjs +1295 -0
- package/scripts/audit/audit-components.cjs +260 -0
- package/scripts/audit/audit-dependencies.cjs +395 -0
- package/scripts/audit/audit-rbac.cjs +954 -0
- package/scripts/audit/audit-standards.cjs +1268 -0
- package/scripts/audit/index.cjs +1898 -194
- package/scripts/install-cursor-rules.cjs +259 -8
- package/scripts/validate-master.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/ContextSelector/ContextSelector.tsx +42 -39
- package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
- package/src/components/DataTable/components/DataTableBody.tsx +55 -31
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +7 -2
- package/src/components/DataTable/components/ImportModal.tsx +4 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/core/DataTableContext.tsx +1 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -0
- package/src/components/DateTimeField/DateTimeField.tsx +20 -20
- package/src/components/DateTimeField/README.md +5 -2
- package/src/components/Dialog/Dialog.test.tsx +361 -318
- package/src/components/Dialog/Dialog.tsx +1154 -323
- package/src/components/Dialog/index.ts +3 -3
- package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
- package/src/components/FileDisplay/FileDisplay.tsx +28 -22
- package/src/components/Form/Form.test.tsx +9 -10
- package/src/components/Form/Form.tsx +369 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
- package/src/components/LoginForm/LoginForm.tsx +2 -2
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
- package/src/components/PaceAppLayout/README.md +10 -9
- package/src/components/PaceAppLayout/test-setup.tsx +40 -31
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
- package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
- package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
- package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
- package/src/components/Select/Select.tsx +23 -21
- package/src/components/Select/types.ts +1 -1
- package/src/components/UserMenu/UserMenu.test.tsx +38 -6
- package/src/components/UserMenu/UserMenu.tsx +39 -34
- package/src/components/index.ts +3 -4
- package/src/eslint-rules/index.cjs +22 -0
- package/src/eslint-rules/rules/compliance.cjs +348 -0
- package/src/eslint-rules/rules/components.cjs +113 -0
- package/src/eslint-rules/rules/imports.cjs +102 -0
- package/src/eslint-rules/rules/rbac.cjs +790 -0
- package/src/eslint-rules/utils/helpers.cjs +42 -0
- package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +62 -190
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +19 -9
- package/src/hooks/useAppConfig.ts +26 -24
- package/src/hooks/useEventTheme.test.ts +211 -233
- package/src/hooks/useEventTheme.ts +19 -28
- package/src/hooks/useEvents.ts +11 -7
- package/src/hooks/useKeyboardShortcuts.ts +1 -1
- package/src/hooks/useOrganisationPermissions.ts +9 -11
- package/src/hooks/useOrganisations.ts +13 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +16 -1
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
- package/src/rbac/README.md +20 -20
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useRBAC.test.ts +21 -3
- package/src/rbac/hooks/useRBAC.ts +4 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
- package/src/rbac/hooks/useResourcePermissions.ts +182 -63
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/permissions.ts +17 -17
- package/src/rbac/utils/contextValidator.ts +45 -7
- package/src/services/AuthService.ts +132 -23
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +155 -58
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +4 -0
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/formatting/formatTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-E7YQZD7D.js +0 -175
- package/dist/DataTable-E7YQZD7D.js.map +0 -1
- package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
- package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
- package/dist/api-6LVZTHDS.js +0 -52
- package/dist/api-6LVZTHDS.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-36LVWXB2.js +0 -227
- package/dist/chunk-36LVWXB2.js.map +0 -1
- package/dist/chunk-3LPHPB62.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-5EC5MEWX.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6SOIHG6Z.js.map +0 -1
- package/dist/chunk-7JPAB3T5.js.map +0 -1
- package/dist/chunk-ATKZM7RX.js +0 -2053
- package/dist/chunk-ATKZM7RX.js.map +0 -1
- package/dist/chunk-AVMLPIM7.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-I6DAQMWX.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NN6WWZ5U.js.map +0 -1
- package/dist/chunk-OEWDTMG7.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-YKRAFF5K.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-OOPCLPZW.js +0 -9
- package/dist/contextValidator-OOPCLPZW.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/eslint-rules/pace-core-compliance.cjs +0 -510
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
package/docs/rbac/README.md
CHANGED
|
@@ -12,6 +12,8 @@ The PACE Core RBAC (Role-Based Access Control) system provides comprehensive per
|
|
|
12
12
|
|
|
13
13
|
## 🚨 Critical Rules (Follow These or It Won't Work)
|
|
14
14
|
|
|
15
|
+
> **📋 IMPORTANT**: See [RBAC Contract](./RBAC_CONTRACT.md) for the complete, enforceable contract. This section provides a quick overview.
|
|
16
|
+
|
|
15
17
|
**MANDATORY Setup Steps (in order):**
|
|
16
18
|
|
|
17
19
|
1. **Call `setupRBAC(supabase)` FIRST** - Must be called before any RBAC components or hooks
|
|
@@ -42,6 +44,8 @@ The PACE Core RBAC (Role-Based Access Control) system provides comprehensive per
|
|
|
42
44
|
6. **App name must match exactly** - Environment variable must match `rbac_apps.name` (case-sensitive)
|
|
43
45
|
7. **Never query RBAC tables directly** - Always use `PagePermissionGuard` or RBAC API functions
|
|
44
46
|
|
|
47
|
+
**⚠️ Contract Compliance**: All consuming apps must comply with the [RBAC Contract](./RBAC_CONTRACT.md). Violations will result in build errors.
|
|
48
|
+
|
|
45
49
|
## 🚀 Quick Start
|
|
46
50
|
|
|
47
51
|
```tsx
|
|
@@ -62,6 +66,8 @@ function MyComponent() {
|
|
|
62
66
|
|
|
63
67
|
## 📖 Core Concepts
|
|
64
68
|
|
|
69
|
+
- **[RBAC Contract](./RBAC_CONTRACT.md)** - ⚠️ **START HERE** - The definitive, enforceable contract (MUST read)
|
|
70
|
+
- **[Migration Guide](./MIGRATION_GUIDE.md)** - Migrating to RBAC Contract v2.0.0
|
|
65
71
|
- **[Quick Start](./quick-start.md)** - Get up and running in 10 minutes (foolproof guide for organisation-based apps)
|
|
66
72
|
- **[Event-Based Apps](./event-based-apps.md)** - Get up and running in 10 minutes (foolproof guide for event-based apps)
|
|
67
73
|
- **[API Reference](./api-reference.md)** - Complete API documentation
|
|
@@ -138,11 +144,14 @@ graph TD
|
|
|
138
144
|
- `useCan` - Check individual permissions
|
|
139
145
|
- `usePermissions` - Get all permissions for a scope
|
|
140
146
|
- `useAccessLevel` - Get user's access level
|
|
141
|
-
- `useMultiplePermissions` - Check multiple permissions efficiently
|
|
147
|
+
- `useMultiplePermissions` - Check multiple permissions efficiently (covers any/all logic)
|
|
148
|
+
- `useResourcePermissions` - Resource CRUD permissions
|
|
149
|
+
- `useSecureSupabase` - Secure Supabase client access
|
|
142
150
|
|
|
143
151
|
### Components
|
|
144
|
-
- `
|
|
145
|
-
- `
|
|
152
|
+
- `PagePermissionGuard` - Page-level permission protection (single canonical component)
|
|
153
|
+
- `NavigationGuard` - Navigation item protection
|
|
154
|
+
- `AccessDenied` - Standard access denied component
|
|
146
155
|
|
|
147
156
|
### Utilities
|
|
148
157
|
- `isPermitted` - Server-side permission checking
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
---
|
|
2
|
+
lastUpdated: 2025-01-28T00:00:00+11:00
|
|
3
|
+
version: 0.6.0
|
|
4
|
+
reviewedBy: rbac-compliance-audit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Edge Functions RBAC Guide
|
|
8
|
+
|
|
9
|
+
**📚 Related**: [RBAC Compliance Guide](../standards/09-rbac-compliance.md) | [RBAC API Reference](./api-reference.md)
|
|
10
|
+
|
|
11
|
+
This guide explains how to use pace-core RBAC APIs in Edge Functions (Deno serverless functions). **There are NO exceptions** - Edge Functions MUST use pace-core APIs, not custom RBAC helpers.
|
|
12
|
+
|
|
13
|
+
## Why No Exceptions?
|
|
14
|
+
|
|
15
|
+
Edge Functions cannot use React hooks (they're Deno-based serverless functions), but pace-core provides programmatic APIs that work outside React:
|
|
16
|
+
|
|
17
|
+
- ✅ `isPermitted()` - Programmatic permission checking API
|
|
18
|
+
- ✅ `setupRBAC()` - Initialize RBAC engine with Supabase client
|
|
19
|
+
- ✅ `getAccessLevel()` - Get user access level
|
|
20
|
+
- ✅ `getRoleContext()` - Get user role context
|
|
21
|
+
|
|
22
|
+
**Custom RBAC helpers are FORBIDDEN** because they:
|
|
23
|
+
- Bypass security validation
|
|
24
|
+
- Skip audit logging
|
|
25
|
+
- Miss caching optimizations
|
|
26
|
+
- Duplicate functionality that pace-core already provides
|
|
27
|
+
|
|
28
|
+
## Correct Pattern
|
|
29
|
+
|
|
30
|
+
### Step 1: Create Supabase Client
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createClient } from 'jsr:@supabase/supabase-js@2';
|
|
34
|
+
|
|
35
|
+
Deno.serve(async (req: Request) => {
|
|
36
|
+
// Extract auth token from request
|
|
37
|
+
const authHeader = req.headers.get('Authorization');
|
|
38
|
+
if (!authHeader) {
|
|
39
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Create Supabase client with auth header
|
|
43
|
+
const supabase = createClient(
|
|
44
|
+
Deno.env.get('SUPABASE_URL') ?? '',
|
|
45
|
+
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
|
|
46
|
+
{
|
|
47
|
+
global: {
|
|
48
|
+
headers: { Authorization: authHeader },
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Step 2: Get User from Session
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Get authenticated user
|
|
58
|
+
const { data: { user }, error: authError } = await supabase.auth.getUser();
|
|
59
|
+
if (authError || !user) {
|
|
60
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Step 3: Setup RBAC
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Import pace-core RBAC functions
|
|
68
|
+
import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
|
|
69
|
+
|
|
70
|
+
// Setup RBAC (MUST be called before using isPermitted)
|
|
71
|
+
setupRBAC(supabase);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Step 4: Extract Organisation Context
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Extract organisation context from request
|
|
78
|
+
// Option 1: From headers
|
|
79
|
+
const organisationId = req.headers.get('x-organisation-id');
|
|
80
|
+
|
|
81
|
+
// Option 2: From request body
|
|
82
|
+
if (!organisationId) {
|
|
83
|
+
const body = await req.json();
|
|
84
|
+
organisationId = body.organisationId;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Option 3: From query parameters
|
|
88
|
+
if (!organisationId) {
|
|
89
|
+
const url = new URL(req.url);
|
|
90
|
+
organisationId = url.searchParams.get('organisationId');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!organisationId) {
|
|
94
|
+
return new Response(
|
|
95
|
+
JSON.stringify({ error: 'Organisation context required' }),
|
|
96
|
+
{ status: 400 }
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step 5: Check Permission
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Check permission using pace-core API
|
|
105
|
+
const hasPermission = await isPermitted({
|
|
106
|
+
userId: user.id,
|
|
107
|
+
scope: {
|
|
108
|
+
organisationId,
|
|
109
|
+
eventId: req.headers.get('x-event-id'), // Optional
|
|
110
|
+
appId: req.headers.get('x-app-id'), // Optional
|
|
111
|
+
},
|
|
112
|
+
permission: 'read:dashboard',
|
|
113
|
+
pageId: 'dashboard' // Optional, but recommended
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (!hasPermission) {
|
|
117
|
+
return new Response(
|
|
118
|
+
JSON.stringify({ error: 'Permission denied' }),
|
|
119
|
+
{ status: 403 }
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Proceed with function logic
|
|
124
|
+
return new Response(JSON.stringify({ success: true }));
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Complete Example
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// supabase/functions/protected-endpoint/index.ts
|
|
132
|
+
import { createClient } from 'jsr:@supabase/supabase-js@2';
|
|
133
|
+
import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
|
|
134
|
+
|
|
135
|
+
Deno.serve(async (req: Request) => {
|
|
136
|
+
try {
|
|
137
|
+
// 1. Extract auth token
|
|
138
|
+
const authHeader = req.headers.get('Authorization');
|
|
139
|
+
if (!authHeader) {
|
|
140
|
+
return new Response(
|
|
141
|
+
JSON.stringify({ error: 'Unauthorized' }),
|
|
142
|
+
{ status: 401, headers: { 'Content-Type': 'application/json' } }
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 2. Create Supabase client
|
|
147
|
+
const supabase = createClient(
|
|
148
|
+
Deno.env.get('SUPABASE_URL') ?? '',
|
|
149
|
+
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
|
|
150
|
+
{
|
|
151
|
+
global: {
|
|
152
|
+
headers: { Authorization: authHeader },
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// 3. Get authenticated user
|
|
158
|
+
const { data: { user }, error: authError } = await supabase.auth.getUser();
|
|
159
|
+
if (authError || !user) {
|
|
160
|
+
return new Response(
|
|
161
|
+
JSON.stringify({ error: 'Unauthorized' }),
|
|
162
|
+
{ status: 401, headers: { 'Content-Type': 'application/json' } }
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 4. Setup RBAC
|
|
167
|
+
setupRBAC(supabase);
|
|
168
|
+
|
|
169
|
+
// 5. Extract organisation context
|
|
170
|
+
const organisationId = req.headers.get('x-organisation-id') ||
|
|
171
|
+
(await req.json().catch(() => ({}))).organisationId;
|
|
172
|
+
|
|
173
|
+
if (!organisationId) {
|
|
174
|
+
return new Response(
|
|
175
|
+
JSON.stringify({ error: 'Organisation context required' }),
|
|
176
|
+
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 6. Check permission
|
|
181
|
+
const hasPermission = await isPermitted({
|
|
182
|
+
userId: user.id,
|
|
183
|
+
scope: { organisationId },
|
|
184
|
+
permission: 'read:dashboard',
|
|
185
|
+
pageId: 'dashboard'
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (!hasPermission) {
|
|
189
|
+
return new Response(
|
|
190
|
+
JSON.stringify({ error: 'Permission denied' }),
|
|
191
|
+
{ status: 403, headers: { 'Content-Type': 'application/json' } }
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 7. Execute function logic
|
|
196
|
+
const result = {
|
|
197
|
+
message: 'Access granted',
|
|
198
|
+
userId: user.id,
|
|
199
|
+
organisationId
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
return new Response(
|
|
203
|
+
JSON.stringify(result),
|
|
204
|
+
{
|
|
205
|
+
status: 200,
|
|
206
|
+
headers: { 'Content-Type': 'application/json' }
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error('Edge Function error:', error);
|
|
211
|
+
return new Response(
|
|
212
|
+
JSON.stringify({ error: 'Internal server error' }),
|
|
213
|
+
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Migration Guide: Removing Custom RBAC Helpers
|
|
220
|
+
|
|
221
|
+
If you have existing Edge Functions with custom RBAC helpers, follow these steps:
|
|
222
|
+
|
|
223
|
+
### Step 1: Identify Custom Helpers
|
|
224
|
+
|
|
225
|
+
Search for custom RBAC helpers:
|
|
226
|
+
```bash
|
|
227
|
+
# Find files with custom RBAC helpers
|
|
228
|
+
grep -r "rbac_check_permission_simplified" supabase/functions/
|
|
229
|
+
grep -r "function.*checkPermission" supabase/functions/
|
|
230
|
+
grep -r "pace-core-compliance-exception" supabase/functions/
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Step 2: Replace Custom Helper with pace-core API
|
|
234
|
+
|
|
235
|
+
**Before (❌ FORBIDDEN):**
|
|
236
|
+
```typescript
|
|
237
|
+
// supabase/functions/_shared/rbac.ts
|
|
238
|
+
export async function checkPermission(
|
|
239
|
+
supabase: SupabaseClient,
|
|
240
|
+
userId: string,
|
|
241
|
+
permission: string,
|
|
242
|
+
organisationId: string
|
|
243
|
+
): Promise<boolean> {
|
|
244
|
+
const { data, error } = await supabase.rpc('rbac_check_permission_simplified', {
|
|
245
|
+
p_user_id: userId,
|
|
246
|
+
p_permission: permission,
|
|
247
|
+
p_organisation_id: organisationId
|
|
248
|
+
});
|
|
249
|
+
return data === true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// supabase/functions/my-function/index.ts
|
|
253
|
+
import { checkPermission } from '../_shared/rbac.ts';
|
|
254
|
+
|
|
255
|
+
const hasPermission = await checkPermission(supabase, user.id, 'read:dashboard', orgId);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**After (✅ CORRECT):**
|
|
259
|
+
```typescript
|
|
260
|
+
// supabase/functions/my-function/index.ts
|
|
261
|
+
import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
|
|
262
|
+
|
|
263
|
+
// Setup RBAC once
|
|
264
|
+
setupRBAC(supabase);
|
|
265
|
+
|
|
266
|
+
// Use pace-core API directly
|
|
267
|
+
const hasPermission = await isPermitted({
|
|
268
|
+
userId: user.id,
|
|
269
|
+
scope: { organisationId: orgId },
|
|
270
|
+
permission: 'read:dashboard',
|
|
271
|
+
pageId: 'dashboard'
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Step 3: Remove Custom Helper Files
|
|
276
|
+
|
|
277
|
+
After migrating all Edge Functions:
|
|
278
|
+
```bash
|
|
279
|
+
# Remove custom RBAC helper file
|
|
280
|
+
rm supabase/functions/_shared/rbac.ts
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Step 4: Update All Edge Functions
|
|
284
|
+
|
|
285
|
+
Update each Edge Function to:
|
|
286
|
+
1. Import `setupRBAC` and `isPermitted` from pace-core
|
|
287
|
+
2. Call `setupRBAC(supabase)` before permission checks
|
|
288
|
+
3. Use `isPermitted()` with complete `PermissionCheck` input
|
|
289
|
+
4. Remove imports of custom RBAC helpers
|
|
290
|
+
|
|
291
|
+
## Common Mistakes
|
|
292
|
+
|
|
293
|
+
### ❌ Mistake 1: Calling RPC Directly
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// ❌ FORBIDDEN
|
|
297
|
+
const { data } = await supabase.rpc('rbac_check_permission_simplified', {
|
|
298
|
+
p_user_id: userId,
|
|
299
|
+
p_permission: 'read:dashboard'
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Fix:**
|
|
304
|
+
```typescript
|
|
305
|
+
// ✅ CORRECT
|
|
306
|
+
setupRBAC(supabase);
|
|
307
|
+
const hasPermission = await isPermitted({
|
|
308
|
+
userId,
|
|
309
|
+
scope: { organisationId },
|
|
310
|
+
permission: 'read:dashboard'
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### ❌ Mistake 2: Forgetting to Setup RBAC
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// ❌ FORBIDDEN - Missing setupRBAC
|
|
318
|
+
import { isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
|
|
319
|
+
|
|
320
|
+
const hasPermission = await isPermitted({ ... }); // Will fail!
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Fix:**
|
|
324
|
+
```typescript
|
|
325
|
+
// ✅ CORRECT
|
|
326
|
+
import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
|
|
327
|
+
|
|
328
|
+
setupRBAC(supabase); // MUST be called first
|
|
329
|
+
const hasPermission = await isPermitted({ ... });
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### ❌ Mistake 3: Missing Organisation Context
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
// ❌ FORBIDDEN - Missing organisationId
|
|
336
|
+
const hasPermission = await isPermitted({
|
|
337
|
+
userId: user.id,
|
|
338
|
+
scope: {}, // Missing organisationId
|
|
339
|
+
permission: 'read:dashboard'
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Fix:**
|
|
344
|
+
```typescript
|
|
345
|
+
// ✅ CORRECT
|
|
346
|
+
const organisationId = req.headers.get('x-organisation-id');
|
|
347
|
+
if (!organisationId) {
|
|
348
|
+
return new Response(JSON.stringify({ error: 'Organisation context required' }), { status: 400 });
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const hasPermission = await isPermitted({
|
|
352
|
+
userId: user.id,
|
|
353
|
+
scope: { organisationId },
|
|
354
|
+
permission: 'read:dashboard'
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Verification Checklist
|
|
359
|
+
|
|
360
|
+
Before deploying Edge Functions, verify:
|
|
361
|
+
|
|
362
|
+
- [ ] `setupRBAC(supabase)` is called before any permission checks
|
|
363
|
+
- [ ] `isPermitted()` is used instead of custom helpers
|
|
364
|
+
- [ ] No direct calls to `rbac_check_permission_simplified` RPC
|
|
365
|
+
- [ ] Organisation context is extracted from request
|
|
366
|
+
- [ ] User authentication is verified before permission checks
|
|
367
|
+
- [ ] Error handling for missing auth/context
|
|
368
|
+
- [ ] No custom RBAC helper files exist
|
|
369
|
+
- [ ] All Edge Functions follow the correct pattern
|
|
370
|
+
|
|
371
|
+
## Related Documentation
|
|
372
|
+
|
|
373
|
+
- [RBAC Compliance Guide](../standards/09-rbac-compliance.md) - Complete compliance rules
|
|
374
|
+
- [RBAC API Reference](./api-reference.md) - Complete API documentation
|
|
375
|
+
- [RBAC Quick Start](./quick-start.md) - Getting started guide
|
|
376
|
+
|
|
@@ -229,38 +229,6 @@ function MyComponent() {
|
|
|
229
229
|
}
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
## Audit Script Detection
|
|
233
|
-
|
|
234
|
-
The pace-core audit script comprehensively detects insecure client usage:
|
|
235
|
-
|
|
236
|
-
```bash
|
|
237
|
-
npm run audit
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
The audit will report violations including:
|
|
241
|
-
- ✅ Direct `createClient` imports from `@supabase/supabase-js`
|
|
242
|
-
- ✅ Direct `createClient()` function calls
|
|
243
|
-
- ✅ Usage of non-secure clients for database queries (`.from()` calls)
|
|
244
|
-
- ✅ Files that import `createClient` but don't use `useSecureSupabase()`
|
|
245
|
-
- ✅ Variables created with `createClient()` that are used for queries
|
|
246
|
-
|
|
247
|
-
**Example audit output**:
|
|
248
|
-
```
|
|
249
|
-
❌ Direct Supabase client usage detected
|
|
250
|
-
File: src/components/UserList.tsx
|
|
251
|
-
Line: 15
|
|
252
|
-
Variable: supabase
|
|
253
|
-
Table: users
|
|
254
|
-
Reason: Direct Supabase client usage detected. Variable 'supabase' is created with createClient() and used for database queries. You MUST use useSecureSupabase() instead to ensure RLS policies and organisation context are enforced.
|
|
255
|
-
Recommendation: Replace with: import { useSecureSupabase } from '@jmruthers/pace-core/rbac'; const supabase = useSecureSupabase();
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
The audit tool provides the same level of detection as the ESLint rule, making it useful for:
|
|
259
|
-
- Pre-commit checks
|
|
260
|
-
- CI/CD pipelines
|
|
261
|
-
- Code reviews
|
|
262
|
-
- Migration validation
|
|
263
|
-
|
|
264
232
|
## Best Practices
|
|
265
233
|
|
|
266
234
|
1. **Always use `useSecureSupabase()`** in React components
|
|
@@ -268,7 +236,6 @@ The audit tool provides the same level of detection as the ESLint rule, making i
|
|
|
268
236
|
3. **Never import `createClient`** from `@supabase/supabase-js` in component files
|
|
269
237
|
4. **Verify client security** in critical code paths (optional but recommended)
|
|
270
238
|
5. **Run ESLint** regularly to catch violations early
|
|
271
|
-
6. **Run audit script** before deploying to catch any missed violations
|
|
272
239
|
|
|
273
240
|
## Troubleshooting
|
|
274
241
|
|
|
@@ -324,7 +291,6 @@ The protection system provides:
|
|
|
324
291
|
- ✅ **Runtime warnings** to alert developers in development mode
|
|
325
292
|
- ✅ **Type safety** to verify client security
|
|
326
293
|
- ✅ **Automatic marking** of secure clients
|
|
327
|
-
- ✅ **Audit scripts** to catch violations before deployment
|
|
328
294
|
|
|
329
295
|
By following these guidelines, you ensure that all database operations respect organisation context and RLS policies, preventing security vulnerabilities and data leakage.
|
|
330
296
|
|