@jmruthers/pace-core 0.6.5 → 0.6.7
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/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.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-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -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 +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- 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 +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- 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-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- 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-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -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 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- 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 +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -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 +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- 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/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- 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/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- 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 +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- 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/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/README.md +1 -1
- 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/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.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-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.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-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.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/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- 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/04-code-style-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/index.cjs +0 -223
- 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/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- 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
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
lastUpdated: 2025-01-02T00:00:00+11:00
|
|
3
|
-
version: 0.5.182
|
|
4
|
-
reviewedBy: rls-audit-and-fixes
|
|
5
|
-
---
|
|
1
|
+
# Security & RBAC Standards
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
**🤖 Cursor Rule**: See [06-security-rbac.mdc](../../cursor-rules/06-security-rbac.mdc) for AI-optimized directives that automatically enforce RBAC contract compliance (ESLint-enforced).
|
|
8
4
|
|
|
9
5
|
## Purpose
|
|
10
6
|
|
|
11
7
|
Define standards for Row-Level Security (RLS) policies and Role-Based Access Control (RBAC) integration to ensure security, performance, and maintainability.
|
|
12
8
|
|
|
9
|
+
**Note:** General performance optimization patterns (React, caching, bundle size) are covered in [Operations Standards](./9-operations-standards.md). This document focuses on RLS-specific performance requirements.
|
|
10
|
+
|
|
13
11
|
## Principles
|
|
14
12
|
|
|
15
13
|
- **Performance First**: All RLS policies must use optimized helper functions
|
|
@@ -101,16 +99,36 @@ FOR SELECT USING (
|
|
|
101
99
|
);
|
|
102
100
|
```
|
|
103
101
|
|
|
102
|
+
## Helper Selection Quick Guide
|
|
103
|
+
|
|
104
|
+
| Scenario | Helper(s) to use | Notes |
|
|
105
|
+
|----------|------------------|-------|
|
|
106
|
+
| Organisation-scoped rows | `check_user_organisation_access(organisation_id)` | Always check `organisation_id IS NOT NULL` first. |
|
|
107
|
+
| Page-permission checks | `check_rbac_permission_with_context(..., get_app_id('APP'))` | Use the wrapper instead of inline `rbac_check_permission_simplified` + `auth.uid()`. |
|
|
108
|
+
| Event-scoped rows | `check_user_event_access(event_id)` | Combine with permission wrapper when pages require it. |
|
|
109
|
+
| Public rows | `check_public_event_access(event_id)` or `is_public = true` | Keep anonymous and authenticated policies separate. |
|
|
110
|
+
| User-owned rows | `get_effective_user_id() = user_id` | Use when `organisation_id IS NULL`. |
|
|
111
|
+
| Service role bypass | `is_service_role()` | Put first in OR chains; use sparingly. |
|
|
112
|
+
|
|
113
|
+
## RLS Helper Requirements (enforced)
|
|
114
|
+
|
|
115
|
+
- Helper functions **must** be `STABLE`, `SECURITY DEFINER`, and `SET search_path TO public`.
|
|
116
|
+
- **Never** inline `auth.uid()`, `auth.role()`, or `current_setting()` inside policies.
|
|
117
|
+
- Use `get_app_id()` for app UUIDs (do not hardcode UUIDs or call legacy getters).
|
|
118
|
+
- Avoid subqueries inside policies; move lookups into helpers.
|
|
119
|
+
|
|
104
120
|
## Standard Helper Functions
|
|
105
121
|
|
|
106
122
|
### Core Helper Functions
|
|
107
123
|
|
|
108
124
|
These functions are available for use in RLS policies:
|
|
109
125
|
|
|
110
|
-
#### `is_super_admin()`
|
|
126
|
+
#### `is_super_admin(p_user_id UUID)`
|
|
111
127
|
- **Returns**: `boolean`
|
|
112
|
-
- **Purpose**: Checks if
|
|
113
|
-
- **Usage**: `is_super_admin()`
|
|
128
|
+
- **Purpose**: Checks if the specified user is a super admin
|
|
129
|
+
- **Usage**: `is_super_admin(safe_get_user_id_for_rls())`
|
|
130
|
+
- **⚠️ CRITICAL**: Always pass an explicit user ID parameter. Never call without parameters.
|
|
131
|
+
- **Security**: This function requires an explicit parameter to prevent fallback strategy vulnerabilities. Use `safe_get_user_id_for_rls()` to get the user ID in RLS policies.
|
|
114
132
|
|
|
115
133
|
#### `check_user_organisation_access(p_organisation_id UUID)`
|
|
116
134
|
- **Returns**: `boolean`
|
|
@@ -212,7 +230,7 @@ FOR SELECT TO authenticated
|
|
|
212
230
|
USING (
|
|
213
231
|
organisation_id IS NOT NULL
|
|
214
232
|
AND (
|
|
215
|
-
is_super_admin()
|
|
233
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
216
234
|
OR check_user_organisation_access(organisation_id)
|
|
217
235
|
)
|
|
218
236
|
);
|
|
@@ -223,6 +241,7 @@ USING (
|
|
|
223
241
|
**Notes:**
|
|
224
242
|
- Always check `organisation_id IS NOT NULL` first
|
|
225
243
|
- Super admin check comes before organisation access check
|
|
244
|
+
- **MUST** use `is_super_admin(safe_get_user_id_for_rls())` with explicit parameter
|
|
226
245
|
- Use `check_user_organisation_access()` for basic membership checks
|
|
227
246
|
|
|
228
247
|
### RBAC Permission-Based Policy
|
|
@@ -236,7 +255,7 @@ FOR SELECT TO authenticated
|
|
|
236
255
|
USING (
|
|
237
256
|
organisation_id IS NOT NULL
|
|
238
257
|
AND (
|
|
239
|
-
is_super_admin()
|
|
258
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
240
259
|
OR check_rbac_permission_with_context(
|
|
241
260
|
'read:page.table_name',
|
|
242
261
|
'table_name',
|
|
@@ -258,7 +277,7 @@ FOR SELECT TO authenticated
|
|
|
258
277
|
USING (
|
|
259
278
|
organisation_id IS NOT NULL
|
|
260
279
|
AND (
|
|
261
|
-
is_super_admin()
|
|
280
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
262
281
|
OR check_rbac_permission_with_context(
|
|
263
282
|
'read:page.table_name',
|
|
264
283
|
'table_name',
|
|
@@ -275,7 +294,7 @@ FOR INSERT TO authenticated
|
|
|
275
294
|
WITH CHECK (
|
|
276
295
|
organisation_id IS NOT NULL
|
|
277
296
|
AND (
|
|
278
|
-
is_super_admin()
|
|
297
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
279
298
|
OR check_rbac_permission_with_context(
|
|
280
299
|
'create:page.table_name',
|
|
281
300
|
'table_name',
|
|
@@ -292,7 +311,7 @@ FOR UPDATE TO authenticated
|
|
|
292
311
|
USING (
|
|
293
312
|
organisation_id IS NOT NULL
|
|
294
313
|
AND (
|
|
295
|
-
is_super_admin()
|
|
314
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
296
315
|
OR check_rbac_permission_with_context(
|
|
297
316
|
'update:page.table_name',
|
|
298
317
|
'table_name',
|
|
@@ -305,7 +324,7 @@ USING (
|
|
|
305
324
|
WITH CHECK (
|
|
306
325
|
organisation_id IS NOT NULL
|
|
307
326
|
AND (
|
|
308
|
-
is_super_admin()
|
|
327
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
309
328
|
OR check_rbac_permission_with_context(
|
|
310
329
|
'update:page.table_name',
|
|
311
330
|
'table_name',
|
|
@@ -322,7 +341,7 @@ FOR DELETE TO authenticated
|
|
|
322
341
|
USING (
|
|
323
342
|
organisation_id IS NOT NULL
|
|
324
343
|
AND (
|
|
325
|
-
is_super_admin()
|
|
344
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
326
345
|
OR check_rbac_permission_with_context(
|
|
327
346
|
'delete:page.table_name',
|
|
328
347
|
'table_name',
|
|
@@ -351,7 +370,7 @@ FOR SELECT TO authenticated
|
|
|
351
370
|
USING (
|
|
352
371
|
organisation_id IS NOT NULL
|
|
353
372
|
AND (
|
|
354
|
-
is_super_admin()
|
|
373
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
355
374
|
OR check_user_event_access(event_id)
|
|
356
375
|
)
|
|
357
376
|
);
|
|
@@ -387,7 +406,7 @@ USING (
|
|
|
387
406
|
organisation_id IS NOT NULL
|
|
388
407
|
AND is_authenticated_user()
|
|
389
408
|
AND (
|
|
390
|
-
is_super_admin()
|
|
409
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
391
410
|
OR check_user_organisation_access(organisation_id)
|
|
392
411
|
)
|
|
393
412
|
)
|
|
@@ -403,6 +422,52 @@ USING (
|
|
|
403
422
|
|
|
404
423
|
**Example:** `file_references`, `pace_address` (can be either organisation or user-scoped)
|
|
405
424
|
|
|
425
|
+
**Real-World Example: File References Table**
|
|
426
|
+
|
|
427
|
+
```sql
|
|
428
|
+
-- Real-world example: file_references table supports both organisation and user-scoped files
|
|
429
|
+
CREATE POLICY "rbac_select_file_references" ON file_references
|
|
430
|
+
FOR SELECT
|
|
431
|
+
USING (
|
|
432
|
+
-- Service role can access all files (for system operations)
|
|
433
|
+
is_service_role()
|
|
434
|
+
OR
|
|
435
|
+
-- Organisation-scoped files (shared within organisation)
|
|
436
|
+
(
|
|
437
|
+
organisation_id IS NOT NULL
|
|
438
|
+
AND is_authenticated_user()
|
|
439
|
+
AND (
|
|
440
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
441
|
+
OR check_user_organisation_access(organisation_id)
|
|
442
|
+
)
|
|
443
|
+
)
|
|
444
|
+
OR
|
|
445
|
+
-- User-scoped files (personal files)
|
|
446
|
+
(
|
|
447
|
+
organisation_id IS NULL
|
|
448
|
+
AND is_authenticated_user()
|
|
449
|
+
AND get_effective_user_id() = user_id
|
|
450
|
+
)
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
-- INSERT policy: Users can upload files to their organisation or personal storage
|
|
454
|
+
CREATE POLICY "rbac_insert_file_references" ON file_references
|
|
455
|
+
FOR INSERT TO authenticated
|
|
456
|
+
WITH CHECK (
|
|
457
|
+
-- Organisation-scoped: Must have organisation access
|
|
458
|
+
(
|
|
459
|
+
organisation_id IS NOT NULL
|
|
460
|
+
AND check_user_organisation_access(organisation_id)
|
|
461
|
+
)
|
|
462
|
+
OR
|
|
463
|
+
-- User-scoped: Must be own user_id
|
|
464
|
+
(
|
|
465
|
+
organisation_id IS NULL
|
|
466
|
+
AND get_effective_user_id() = user_id
|
|
467
|
+
)
|
|
468
|
+
);
|
|
469
|
+
```
|
|
470
|
+
|
|
406
471
|
### Service Role Policy
|
|
407
472
|
|
|
408
473
|
**Use Case:** Allow service_role to bypass RLS for system operations.
|
|
@@ -453,6 +518,66 @@ USING (
|
|
|
453
518
|
|
|
454
519
|
**Example:** `event` (public events), `forms` (published forms)
|
|
455
520
|
|
|
521
|
+
**Real-World Example: Public Event Registration**
|
|
522
|
+
|
|
523
|
+
```sql
|
|
524
|
+
-- Real-world example: Events table with public registration
|
|
525
|
+
-- Public users can view and register for public events
|
|
526
|
+
-- Authenticated users can view all events in their organisation
|
|
527
|
+
|
|
528
|
+
-- Public access: Anonymous users can view public events
|
|
529
|
+
CREATE POLICY "public_select_events" ON events
|
|
530
|
+
FOR SELECT TO anon
|
|
531
|
+
USING (
|
|
532
|
+
is_public = true
|
|
533
|
+
AND organisation_id IS NOT NULL
|
|
534
|
+
AND status = 'published'
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
-- Authenticated access: Users can view events in their organisation
|
|
538
|
+
CREATE POLICY "rbac_select_events" ON events
|
|
539
|
+
FOR SELECT TO authenticated
|
|
540
|
+
USING (
|
|
541
|
+
-- Public events (anyone can see)
|
|
542
|
+
(is_public = true AND organisation_id IS NOT NULL)
|
|
543
|
+
OR
|
|
544
|
+
-- Organisation events (members can see)
|
|
545
|
+
(
|
|
546
|
+
organisation_id IS NOT NULL
|
|
547
|
+
AND (
|
|
548
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
549
|
+
OR check_user_organisation_access(organisation_id)
|
|
550
|
+
)
|
|
551
|
+
)
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
-- Public registration: Anonymous users can create registrations for public events
|
|
555
|
+
CREATE POLICY "public_insert_event_registrations" ON event_registrations
|
|
556
|
+
FOR INSERT TO anon
|
|
557
|
+
WITH CHECK (
|
|
558
|
+
-- Only for public events
|
|
559
|
+
event_id IN (
|
|
560
|
+
SELECT id FROM events
|
|
561
|
+
WHERE is_public = true AND status = 'published'
|
|
562
|
+
)
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
-- Authenticated registration: Users can register for events in their organisation
|
|
566
|
+
CREATE POLICY "rbac_insert_event_registrations" ON event_registrations
|
|
567
|
+
FOR INSERT TO authenticated
|
|
568
|
+
WITH CHECK (
|
|
569
|
+
-- Must have access to the event's organisation
|
|
570
|
+
event_id IN (
|
|
571
|
+
SELECT id FROM events
|
|
572
|
+
WHERE organisation_id IS NOT NULL
|
|
573
|
+
AND (
|
|
574
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
575
|
+
OR check_user_organisation_access(organisation_id)
|
|
576
|
+
)
|
|
577
|
+
)
|
|
578
|
+
);
|
|
579
|
+
```
|
|
580
|
+
|
|
456
581
|
**Combined Public + Authenticated Pattern:**
|
|
457
582
|
```sql
|
|
458
583
|
-- Public access
|
|
@@ -471,7 +596,7 @@ USING (
|
|
|
471
596
|
OR (
|
|
472
597
|
organisation_id IS NOT NULL
|
|
473
598
|
AND (
|
|
474
|
-
is_super_admin()
|
|
599
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
475
600
|
OR check_user_organisation_access(organisation_id)
|
|
476
601
|
)
|
|
477
602
|
)
|
|
@@ -496,7 +621,7 @@ USING (
|
|
|
496
621
|
is_authenticated_user()
|
|
497
622
|
AND organisation_id IS NOT NULL
|
|
498
623
|
AND (
|
|
499
|
-
is_super_admin()
|
|
624
|
+
is_super_admin(safe_get_user_id_for_rls())
|
|
500
625
|
OR check_user_organisation_access(organisation_id)
|
|
501
626
|
)
|
|
502
627
|
)
|
|
@@ -542,7 +667,7 @@ USING (is_authenticated_user());
|
|
|
542
667
|
```sql
|
|
543
668
|
CREATE POLICY "rbac_select_table_name" ON table_name
|
|
544
669
|
FOR SELECT TO authenticated
|
|
545
|
-
USING (is_super_admin());
|
|
670
|
+
USING (is_super_admin(safe_get_user_id_for_rls()));
|
|
546
671
|
```
|
|
547
672
|
|
|
548
673
|
**Example:** `rbac_global_roles`, `rbac_policy_configs`
|
|
@@ -552,20 +677,20 @@ USING (is_super_admin());
|
|
|
552
677
|
-- All operations restricted to super admin
|
|
553
678
|
CREATE POLICY "rbac_select_table_name" ON table_name
|
|
554
679
|
FOR SELECT TO authenticated
|
|
555
|
-
USING (is_super_admin());
|
|
680
|
+
USING (is_super_admin(safe_get_user_id_for_rls()));
|
|
556
681
|
|
|
557
682
|
CREATE POLICY "rbac_insert_table_name" ON table_name
|
|
558
683
|
FOR INSERT TO authenticated
|
|
559
|
-
WITH CHECK (is_super_admin());
|
|
684
|
+
WITH CHECK (is_super_admin(safe_get_user_id_for_rls()));
|
|
560
685
|
|
|
561
686
|
CREATE POLICY "rbac_update_table_name" ON table_name
|
|
562
687
|
FOR UPDATE TO authenticated
|
|
563
|
-
USING (is_super_admin())
|
|
564
|
-
WITH CHECK (is_super_admin());
|
|
688
|
+
USING (is_super_admin(safe_get_user_id_for_rls()))
|
|
689
|
+
WITH CHECK (is_super_admin(safe_get_user_id_for_rls()));
|
|
565
690
|
|
|
566
691
|
CREATE POLICY "rbac_delete_table_name" ON table_name
|
|
567
692
|
FOR DELETE TO authenticated
|
|
568
|
-
USING (is_super_admin());
|
|
693
|
+
USING (is_super_admin(safe_get_user_id_for_rls()));
|
|
569
694
|
```
|
|
570
695
|
|
|
571
696
|
### Common Patterns Summary
|
|
@@ -579,19 +704,122 @@ USING (is_super_admin());
|
|
|
579
704
|
| Service Role | System operations | `is_service_role()` |
|
|
580
705
|
| Public Access | Anonymous users | `check_public_event_access()` or `is_public` flag |
|
|
581
706
|
| Read-Only Types | Reference tables | `is_authenticated_user()` |
|
|
582
|
-
| Super Admin Only | Admin-only tables | `is_super_admin()` |
|
|
707
|
+
| Super Admin Only | Admin-only tables | `is_super_admin(safe_get_user_id_for_rls())` |
|
|
583
708
|
|
|
584
709
|
### Policy Best Practices
|
|
585
710
|
|
|
586
711
|
1. **Always use helper functions** - Never inline `auth.uid()`, `auth.role()`, or `current_setting()`
|
|
587
712
|
2. **Check NULL first** - Always check `organisation_id IS NOT NULL` before using it
|
|
588
|
-
3. **Super admin first** - Super admin checks should come before other checks in OR conditions
|
|
713
|
+
3. **Super admin first** - Super admin checks should come before other checks in OR conditions. **MUST** use `is_super_admin(safe_get_user_id_for_rls())` with explicit parameter - never call without parameters.
|
|
589
714
|
4. **Service role first** - Service role checks should be the first condition in multi-condition policies
|
|
590
715
|
5. **Consistent naming** - Follow the naming convention: `rbac_{operation}_{table}_{scope}`
|
|
591
716
|
6. **Document exceptions** - If a policy deviates from standard patterns, add a comment explaining why
|
|
592
717
|
7. **Test thoroughly** - Test with different user roles (super_admin, org_admin, member, anon)
|
|
593
718
|
8. **Avoid `true OR ...`** - Never use `true OR ...` conditions as they bypass all security checks
|
|
594
719
|
|
|
720
|
+
## Edge Functions and Serverless Functions
|
|
721
|
+
|
|
722
|
+
**Edge Functions (Deno serverless functions) MUST use pace-core's `isPermitted()` API function.** Edge Functions cannot use React hooks, but pace-core provides programmatic APIs that work outside React.
|
|
723
|
+
|
|
724
|
+
### ✅ CORRECT - Edge Function Pattern
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
// supabase/functions/my-function/index.ts
|
|
728
|
+
import { createClient } from 'jsr:@supabase/supabase-js@2';
|
|
729
|
+
import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
|
|
730
|
+
|
|
731
|
+
Deno.serve(async (req: Request) => {
|
|
732
|
+
// 1. Create Supabase client from request headers
|
|
733
|
+
const authHeader = req.headers.get('Authorization');
|
|
734
|
+
if (!authHeader) {
|
|
735
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const supabase = createClient(
|
|
739
|
+
Deno.env.get('SUPABASE_URL') ?? '',
|
|
740
|
+
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
|
|
741
|
+
{
|
|
742
|
+
global: {
|
|
743
|
+
headers: { Authorization: authHeader },
|
|
744
|
+
},
|
|
745
|
+
}
|
|
746
|
+
);
|
|
747
|
+
|
|
748
|
+
// 2. Get user from session
|
|
749
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
750
|
+
if (!user) {
|
|
751
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// 3. Setup RBAC (required before using isPermitted)
|
|
755
|
+
setupRBAC(supabase);
|
|
756
|
+
|
|
757
|
+
// 4. Extract organisation context from request
|
|
758
|
+
const organisationId = req.headers.get('x-organisation-id') ||
|
|
759
|
+
(await req.json()).organisationId;
|
|
760
|
+
|
|
761
|
+
if (!organisationId) {
|
|
762
|
+
return new Response(JSON.stringify({ error: 'Organisation context required' }), { status: 400 });
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// 5. Check permission using pace-core API
|
|
766
|
+
const hasPermission = await isPermitted({
|
|
767
|
+
userId: user.id,
|
|
768
|
+
scope: { organisationId },
|
|
769
|
+
permission: 'read:dashboard',
|
|
770
|
+
pageId: 'dashboard'
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
if (!hasPermission) {
|
|
774
|
+
return new Response(JSON.stringify({ error: 'Permission denied' }), { status: 403 });
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// 6. Proceed with function logic
|
|
778
|
+
return new Response(JSON.stringify({ success: true }));
|
|
779
|
+
});
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
### ❌ FORBIDDEN - Custom RBAC Helper in Edge Functions
|
|
783
|
+
|
|
784
|
+
**Creating custom RBAC helper functions in Edge Functions is FORBIDDEN.** pace-core provides all necessary APIs.
|
|
785
|
+
|
|
786
|
+
```typescript
|
|
787
|
+
// ❌ FORBIDDEN - Custom RBAC helper
|
|
788
|
+
// supabase/functions/_shared/rbac.ts
|
|
789
|
+
export async function checkPermission(userId: string, permission: string) {
|
|
790
|
+
// Custom logic that bypasses pace-core
|
|
791
|
+
const { data } = await supabase.rpc('rbac_check_permission_simplified', {
|
|
792
|
+
p_user_id: userId,
|
|
793
|
+
p_permission: permission
|
|
794
|
+
});
|
|
795
|
+
return data;
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### Why No Exceptions
|
|
800
|
+
|
|
801
|
+
- pace-core provides `isPermitted()` API that works outside React
|
|
802
|
+
- `setupRBAC()` initializes the engine with a Supabase client
|
|
803
|
+
- No custom helpers needed - use pace-core APIs directly
|
|
804
|
+
- Custom helpers bypass security validation, caching, and audit logging
|
|
805
|
+
|
|
806
|
+
### Edge Function Requirements
|
|
807
|
+
|
|
808
|
+
1. **MUST** call `setupRBAC(supabase)` before using `isPermitted()`
|
|
809
|
+
2. **MUST** extract `userId` from Supabase auth session
|
|
810
|
+
3. **MUST** extract `organisationId` from request (headers, body, or query params)
|
|
811
|
+
4. **MUST** use `isPermitted()` with complete `PermissionCheck` input
|
|
812
|
+
5. **MUST NOT** create custom RBAC helper functions
|
|
813
|
+
6. **MUST NOT** call `rbac_check_permission_simplified` RPC directly
|
|
814
|
+
|
|
815
|
+
## Security Baseline
|
|
816
|
+
|
|
817
|
+
- Never bypass RLS; validate all inputs and sanitize logs (no tokens/PII).
|
|
818
|
+
- Use safe, user-friendly error messaging.
|
|
819
|
+
- Prefer pace-core security helpers and secure clients (`useSecureSupabase`, RBAC helpers) over custom implementations.
|
|
820
|
+
- Monitor RLS performance (avoid subqueries/InitPlan); keep helpers `STABLE SECURITY DEFINER` with `SET search_path TO public`.
|
|
821
|
+
- **Edge Functions MUST use pace-core `isPermitted()` API - no exceptions allowed.**
|
|
822
|
+
|
|
595
823
|
### Common Pitfalls to Avoid
|
|
596
824
|
|
|
597
825
|
**❌ DON'T:**
|
|
@@ -648,29 +876,23 @@ Tables are assigned to specific apps for RBAC permission checking:
|
|
|
648
876
|
|
|
649
877
|
### Before Merging RLS Changes
|
|
650
878
|
|
|
651
|
-
1. **Run
|
|
652
|
-
```bash
|
|
653
|
-
npm run audit:rls
|
|
654
|
-
```
|
|
655
|
-
This checks for violations and should pass with zero violations.
|
|
656
|
-
|
|
657
|
-
2. **Run Supabase Advisors**:
|
|
879
|
+
1. **Run Supabase Advisors**:
|
|
658
880
|
```bash
|
|
659
881
|
supabase advisors performance
|
|
660
882
|
supabase advisors security
|
|
661
883
|
```
|
|
662
884
|
|
|
663
|
-
|
|
885
|
+
2. **Run Database Tests**:
|
|
664
886
|
```bash
|
|
665
887
|
timeout 120 npm run test:db
|
|
666
888
|
```
|
|
667
889
|
|
|
668
|
-
|
|
890
|
+
3. **Run Application Tests**:
|
|
669
891
|
```bash
|
|
670
892
|
timeout 60 npm run test
|
|
671
893
|
```
|
|
672
894
|
|
|
673
|
-
|
|
895
|
+
4. **Verify Performance**:
|
|
674
896
|
- Use EXPLAIN ANALYZE to verify no InitPlan nodes
|
|
675
897
|
- Verify queries complete in < 1 second
|
|
676
898
|
- Check Supabase Advisors show zero `auth_rls_initplan` warnings
|
|
@@ -686,32 +908,9 @@ Tables are assigned to specific apps for RBAC permission checking:
|
|
|
686
908
|
|
|
687
909
|
### Ongoing RLS Compliance Monitoring
|
|
688
910
|
|
|
689
|
-
**Run
|
|
690
|
-
|
|
691
|
-
```bash
|
|
692
|
-
# Quick audit (recommended before merging PRs)
|
|
693
|
-
npm run audit:rls
|
|
694
|
-
|
|
695
|
-
# Or use test database
|
|
696
|
-
npm run audit:rls:test
|
|
697
|
-
|
|
698
|
-
# For CI/CD (fails on violations)
|
|
699
|
-
npm run audit:rls:ci
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
The audit checks for:
|
|
703
|
-
- Tables with RLS enabled but no policies
|
|
704
|
-
- Policies using inline `auth.uid()` calls
|
|
705
|
-
- Policies using `current_setting()` directly
|
|
706
|
-
- Helper functions missing STABLE/SECURITY DEFINER
|
|
707
|
-
|
|
708
|
-
### Weekly Health Checks
|
|
911
|
+
**Run Supabase advisors regularly** to catch any rogue policies that violate standards:
|
|
709
912
|
|
|
710
|
-
Run weekly:
|
|
711
913
|
```bash
|
|
712
|
-
# RLS compliance audit
|
|
713
|
-
npm run audit:rls
|
|
714
|
-
|
|
715
914
|
# Performance advisors
|
|
716
915
|
supabase advisors performance
|
|
717
916
|
|
|
@@ -772,8 +971,12 @@ date +"%Y%m%d%H%M%S"
|
|
|
772
971
|
|
|
773
972
|
## Related Documentation
|
|
774
973
|
|
|
775
|
-
- [
|
|
776
|
-
- [
|
|
777
|
-
- [
|
|
778
|
-
|
|
974
|
+
- [Standards Overview](./0-standards-overview.md) - Standards system overview
|
|
975
|
+
- [pace-core Compliance](./1-pace-core-compliance-standards.md) - Secure Supabase client usage
|
|
976
|
+
- [Operations](./9-operations-standards.md) - General performance patterns (React, caching, etc.)
|
|
977
|
+
|
|
978
|
+
---
|
|
779
979
|
|
|
980
|
+
**Last Updated:** 2025-01-28
|
|
981
|
+
**Version:** 2.0.0
|
|
982
|
+
**Applies to:** All pace-core and consuming apps
|