@jmruthers/pace-core 0.6.6 → 0.6.8

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.
Files changed (292) hide show
  1. package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +227 -22
  2. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  3. package/audit-tool/audits/02-project-structure.cjs +240 -0
  4. package/audit-tool/audits/03-architecture.cjs +224 -0
  5. package/audit-tool/audits/04-code-quality.cjs +149 -0
  6. package/audit-tool/audits/05-styling.cjs +224 -0
  7. package/audit-tool/audits/06-security-rbac.cjs +554 -0
  8. package/audit-tool/audits/07-api-tech-stack.cjs +355 -0
  9. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  10. package/audit-tool/audits/09-operations.cjs +208 -0
  11. package/audit-tool/index.cjs +295 -0
  12. package/audit-tool/utils/code-utils.cjs +218 -0
  13. package/audit-tool/utils/file-utils.cjs +230 -0
  14. package/audit-tool/utils/report-utils.cjs +380 -0
  15. package/cursor-rules/00-standards-overview.mdc +156 -0
  16. package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
  17. package/cursor-rules/02-project-structure.mdc +37 -5
  18. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
  19. package/cursor-rules/04-code-quality.mdc +419 -0
  20. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
  21. package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
  22. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  23. package/cursor-rules/08-testing-documentation.mdc +324 -0
  24. package/cursor-rules/09-operations.mdc +365 -0
  25. package/dist/DataTable-6RMSCQJ6.js +15 -0
  26. package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  27. package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-CIGSujI2.d.ts} +40 -24
  28. package/dist/{UnifiedAuthProvider-ZT6TIGM7.js → UnifiedAuthProvider-7SNDOWYD.js} +2 -2
  29. package/dist/{api-Y4MQWOFW.js → api-7P7DI652.js} +1 -1
  30. package/dist/{chunk-MAGBIDNS.js → chunk-4DDCYDQ3.js} +8 -7
  31. package/dist/{chunk-BVP2BCJF.js → chunk-5W2A3DRC.js} +10 -9
  32. package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
  33. package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
  34. package/dist/{chunk-3O3WHILE.js → chunk-EF2UGZWY.js} +239 -63
  35. package/dist/{chunk-LAZMKTTF.js → chunk-EURB7QFZ.js} +341 -337
  36. package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
  37. package/dist/{chunk-7TYHROIV.js → chunk-GS5672WG.js} +55 -13
  38. package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
  39. package/dist/{chunk-ZFYPMX46.js → chunk-LX6U42O3.js} +1 -1
  40. package/dist/{chunk-FENMYN2U.js → chunk-MPBLMWVR.js} +3 -3
  41. package/dist/{chunk-ZS5VO5JB.js → chunk-NKHKXPI4.js} +408 -453
  42. package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
  43. package/dist/{chunk-4T7OBVTU.js → chunk-S6ZQKDY6.js} +1 -1
  44. package/dist/{chunk-FTCRZOG2.js → chunk-T5CVK4R3.js} +5 -5
  45. package/dist/{chunk-OHIK3MIO.js → chunk-Z2FNRKF3.js} +13 -13
  46. package/dist/components.d.ts +5 -4
  47. package/dist/components.js +29 -34
  48. package/dist/eslint-rules/index.cjs +22 -9
  49. package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
  50. package/dist/eslint-rules/rules/04-code-quality.cjs +346 -0
  51. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  52. package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +34 -13
  53. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +385 -0
  54. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  55. package/dist/{functions-DHebl8-F.d.ts → functions-lBy5L2ry.d.ts} +1 -1
  56. package/dist/hooks.d.ts +5 -5
  57. package/dist/hooks.js +8 -8
  58. package/dist/index.d.ts +7 -7
  59. package/dist/index.js +21 -20
  60. package/dist/providers.js +2 -2
  61. package/dist/rbac/index.d.ts +1 -1
  62. package/dist/rbac/index.js +8 -8
  63. package/dist/theming/runtime.d.ts +61 -1
  64. package/dist/theming/runtime.js +1 -1
  65. package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
  66. package/dist/types.d.ts +2 -2
  67. package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
  68. package/dist/utils.d.ts +2 -2
  69. package/dist/utils.js +8 -8
  70. package/docs/README.md +1 -1
  71. package/docs/api/modules.md +106 -41
  72. package/docs/api-reference/components.md +18 -20
  73. package/docs/api-reference/hooks.md +80 -80
  74. package/docs/api-reference/types.md +1 -1
  75. package/docs/api-reference/utilities.md +1 -1
  76. package/docs/architecture/README.md +1 -1
  77. package/docs/core-concepts/events.md +3 -3
  78. package/docs/core-concepts/organisations.md +6 -6
  79. package/docs/core-concepts/permissions.md +6 -6
  80. package/docs/documentation-index.md +12 -18
  81. package/docs/getting-started/dependencies.md +23 -0
  82. package/docs/getting-started/documentation-index.md +1 -1
  83. package/docs/getting-started/examples/README.md +4 -4
  84. package/docs/getting-started/examples/full-featured-app.md +1 -1
  85. package/docs/getting-started/faq.md +2 -2
  86. package/docs/getting-started/quick-reference.md +4 -4
  87. package/docs/implementation-guides/app-layout.md +1 -1
  88. package/docs/implementation-guides/authentication.md +15 -15
  89. package/docs/implementation-guides/component-styling.md +1 -1
  90. package/docs/implementation-guides/data-tables.md +127 -34
  91. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  92. package/docs/implementation-guides/dynamic-colors.md +3 -3
  93. package/docs/implementation-guides/file-upload-storage.md +2 -2
  94. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  95. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  96. package/docs/implementation-guides/large-datasets.md +3 -2
  97. package/docs/implementation-guides/organisation-security.md +2 -2
  98. package/docs/implementation-guides/performance.md +2 -2
  99. package/docs/implementation-guides/permission-enforcement.md +1 -1
  100. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  101. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  102. package/docs/rbac/README.md +5 -5
  103. package/docs/rbac/advanced-patterns.md +6 -6
  104. package/docs/rbac/api-reference.md +20 -20
  105. package/docs/rbac/event-based-apps.md +3 -3
  106. package/docs/rbac/examples.md +41 -41
  107. package/docs/rbac/getting-started.md +37 -37
  108. package/docs/rbac/performance.md +1 -1
  109. package/docs/rbac/quick-start.md +52 -52
  110. package/docs/rbac/secure-client-protection.md +1 -1
  111. package/docs/rbac/troubleshooting.md +1 -1
  112. package/docs/security/README.md +5 -5
  113. package/docs/standards/0-standards-overview.md +220 -0
  114. package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +241 -185
  115. package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
  116. package/docs/standards/3-architecture-standards.md +606 -0
  117. package/docs/standards/4-code-quality-standards.md +728 -0
  118. package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
  119. package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
  120. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  121. package/docs/standards/8-testing-documentation-standards.md +401 -0
  122. package/docs/standards/9-operations-standards.md +1102 -0
  123. package/docs/standards/README.md +203 -104
  124. package/docs/troubleshooting/README.md +4 -4
  125. package/docs/troubleshooting/common-issues.md +2 -2
  126. package/docs/troubleshooting/debugging.md +9 -9
  127. package/docs/troubleshooting/migration.md +4 -4
  128. package/eslint-config-pace-core.cjs +50 -20
  129. package/package.json +50 -19
  130. package/scripts/eslint-audit.cjs +123 -0
  131. package/scripts/install-cursor-rules.cjs +11 -243
  132. package/scripts/install-eslint-config.cjs +349 -0
  133. package/scripts/validate-dependencies.cjs +248 -0
  134. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
  135. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  136. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +30 -18
  137. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  138. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  139. package/src/__tests__/templates/accessibility.test.template.tsx +10 -9
  140. package/src/__tests__/templates/component.test.template.tsx +18 -15
  141. package/src/components/AddressField/AddressField.tsx +26 -1
  142. package/src/components/Alert/Alert.test.tsx +86 -22
  143. package/src/components/Alert/Alert.tsx +19 -11
  144. package/src/components/Badge/Badge.tsx +1 -1
  145. package/src/components/Calendar/Calendar.tsx +201 -47
  146. package/src/components/Checkbox/Checkbox.test.tsx +2 -1
  147. package/src/components/ContextSelector/ContextSelector.tsx +108 -126
  148. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  149. package/src/components/DataTable/DataTable.tsx +1 -19
  150. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +6 -2
  151. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +21 -6
  152. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +3 -2
  153. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  154. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  155. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  156. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  157. package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
  158. package/src/components/DataTable/components/EditableRow.tsx +5 -7
  159. package/src/components/DataTable/components/EmptyState.tsx +11 -10
  160. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  161. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  162. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  163. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  164. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  165. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  166. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  167. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  168. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  169. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +45 -27
  170. package/src/components/DataTable/components/index.ts +2 -1
  171. package/src/components/DataTable/types.ts +0 -18
  172. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  173. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  174. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  175. package/src/components/DateTimeField/DateTimeField.tsx +7 -8
  176. package/src/components/Dialog/Dialog.test.tsx +1 -0
  177. package/src/components/Dialog/Dialog.tsx +25 -8
  178. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  179. package/src/components/FileUpload/FileUpload.test.tsx +45 -16
  180. package/src/components/FileUpload/FileUpload.tsx +141 -130
  181. package/src/components/NavigationMenu/NavigationMenu.test.tsx +48 -12
  182. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +9 -9
  183. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +30 -30
  184. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -4
  185. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +7 -1
  186. package/src/components/Progress/Progress.tsx +2 -4
  187. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  188. package/src/components/Select/Select.tsx +86 -77
  189. package/src/components/Select/types.ts +3 -0
  190. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  191. package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
  192. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +8 -5
  193. package/src/hooks/__tests__/useFileUrl.unit.test.ts +4 -0
  194. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +99 -99
  195. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +45 -8
  196. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +22 -2
  197. package/src/hooks/public/usePublicEvent.ts +5 -5
  198. package/src/hooks/public/usePublicEventLogo.ts +5 -5
  199. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  200. package/src/hooks/public/usePublicRouteParams.ts +13 -9
  201. package/src/hooks/useAddressAutocomplete.test.ts +18 -18
  202. package/src/hooks/useAppConfig.ts +2 -2
  203. package/src/hooks/useEventTheme.test.ts +7 -7
  204. package/src/hooks/useEventTheme.ts +2 -1
  205. package/src/hooks/useFileDisplay.ts +2 -2
  206. package/src/hooks/useFileUrl.ts +52 -8
  207. package/src/hooks/useOrganisationSecurity.test.ts +2 -1
  208. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  209. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  210. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  211. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  212. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  213. package/src/providers/__tests__/ProviderLifecycle.test.tsx +38 -38
  214. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  215. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  216. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
  217. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +15 -6
  218. package/src/rbac/__tests__/rbac-functions.test.ts +3 -3
  219. package/src/rbac/api.test.ts +104 -0
  220. package/src/rbac/engine.ts +1 -1
  221. package/src/rbac/hooks/useCan.test.ts +2 -2
  222. package/src/rbac/secureClient.ts +1 -1
  223. package/src/rbac/types/functions.ts +1 -1
  224. package/src/styles/core.css +7 -0
  225. package/src/theming/__tests__/parseEventColours.test.ts +118 -3
  226. package/src/theming/parseEventColours.ts +77 -11
  227. package/src/types/supabase.ts +2 -3
  228. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +9 -9
  229. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  230. package/src/utils/file-reference/__tests__/file-reference.test.ts +4 -0
  231. package/src/utils/formatting/formatDate.test.ts +3 -2
  232. package/src/utils/formatting/formatDateTime.test.ts +2 -2
  233. package/src/utils/google-places/googlePlacesUtils.test.ts +36 -24
  234. package/src/utils/storage/README.md +1 -1
  235. package/src/utils/storage/__tests__/helpers.unit.test.ts +19 -12
  236. package/src/utils/storage/helpers.test.ts +69 -3
  237. package/cursor-rules/01-standards-compliance.mdc +0 -285
  238. package/cursor-rules/04-testing-standards.mdc +0 -270
  239. package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
  240. package/cursor-rules/06-code-quality.mdc +0 -311
  241. package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
  242. package/cursor-rules/10-error-handling-patterns.mdc +0 -179
  243. package/cursor-rules/11-performance-optimization.mdc +0 -169
  244. package/cursor-rules/12-ci-cd-integration.mdc +0 -150
  245. package/dist/DataTable-LRJL4IRV.js +0 -15
  246. package/dist/eslint-rules/rules/compliance.cjs +0 -348
  247. package/dist/eslint-rules/rules/components.cjs +0 -113
  248. package/dist/eslint-rules/rules/imports.cjs +0 -102
  249. package/docs/best-practices/README.md +0 -472
  250. package/docs/best-practices/accessibility.md +0 -604
  251. package/docs/best-practices/common-patterns.md +0 -516
  252. package/docs/best-practices/deployment.md +0 -1103
  253. package/docs/best-practices/performance.md +0 -1328
  254. package/docs/best-practices/security.md +0 -940
  255. package/docs/best-practices/testing.md +0 -1034
  256. package/docs/rbac/compliance/compliance-guide.md +0 -544
  257. package/docs/standards/01-standards-compliance.md +0 -188
  258. package/docs/standards/03-solid-principles.md +0 -39
  259. package/docs/standards/04-testing-standards.md +0 -36
  260. package/docs/standards/05-bug-reports-and-features.md +0 -27
  261. package/docs/standards/06-code-quality.md +0 -34
  262. package/docs/standards/07-tech-stack-compliance.md +0 -30
  263. package/docs/standards/10-error-handling-patterns.md +0 -401
  264. package/docs/standards/11-performance-optimization.md +0 -348
  265. package/docs/standards/12-ci-cd-integration.md +0 -370
  266. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
  267. package/scripts/audit/audit-compliance.cjs +0 -1295
  268. package/scripts/audit/audit-components.cjs +0 -260
  269. package/scripts/audit/audit-rbac.cjs +0 -954
  270. package/scripts/audit/audit-standards.cjs +0 -1268
  271. package/scripts/audit/index.cjs +0 -1927
  272. package/src/components/DataTable/components/DataTableBody.tsx +0 -478
  273. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  274. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  275. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  276. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  277. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  278. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  279. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  280. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  281. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  282. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  283. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  284. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  285. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  286. package/src/components/DataTable/utils/debugTools.ts +0 -514
  287. package/src/eslint-rules/index.cjs +0 -22
  288. package/src/eslint-rules/rules/components.cjs +0 -113
  289. package/src/eslint-rules/rules/imports.cjs +0 -102
  290. package/src/eslint-rules/rules/rbac.cjs +0 -790
  291. package/src/eslint-rules/utils/helpers.cjs +0 -42
  292. package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
@@ -0,0 +1,554 @@
1
+ /**
2
+ * Standard 6: Security & RBAC Audit
3
+ * @package @jmruthers/pace-core
4
+ * @module Audit/Standard6
5
+ *
6
+ * Audits consuming apps for compliance with Standard 6: Security & RBAC.
7
+ * Validates RLS policies in SQL migrations, PagePermissionGuard coverage, and Edge Functions RBAC.
8
+ *
9
+ * Reference: packages/core/docs/standards/6-security-rbac-standards.md
10
+ */
11
+
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+ const { findSQLFiles, findSourceFiles, readFileSafe, getRelativePath, directoryExists } = require('../utils/file-utils.cjs');
15
+ const { getLineNumber, getCodeSnippet, isInCommentOrStringSQL, isInCommentOrString, importsFromPaceCore } = require('../utils/code-utils.cjs');
16
+
17
+ /**
18
+ * Check RLS policy compliance in SQL migrations
19
+ */
20
+ function checkRLSPolicies(consumingAppPath) {
21
+ const issues = [];
22
+
23
+ // Find SQL migration files
24
+ const migrationsPath = path.join(consumingAppPath, 'supabase', 'migrations');
25
+ const altMigrationsPath = path.join(consumingAppPath, 'migrations');
26
+
27
+ const migrationsDir = fs.existsSync(migrationsPath) ? migrationsPath :
28
+ (fs.existsSync(altMigrationsPath) ? altMigrationsPath : null);
29
+
30
+ if (!migrationsDir) {
31
+ return issues; // No migrations directory, skip check
32
+ }
33
+
34
+ const sqlFiles = findSQLFiles(migrationsDir);
35
+
36
+ sqlFiles.forEach(filePath => {
37
+ try {
38
+ const content = readFileSafe(filePath);
39
+ if (!content) {
40
+ return;
41
+ }
42
+
43
+ const relativePath = getRelativePath(filePath, consumingAppPath);
44
+
45
+ // Find CREATE POLICY statements
46
+ const policyPattern = /CREATE\s+POLICY\s+["']?([^"'\s]+)["']?\s+ON\s+(\w+)\s+FOR\s+(\w+)/gi;
47
+ let match;
48
+
49
+ while ((match = policyPattern.exec(content)) !== null) {
50
+ const policyName = match[1];
51
+ const tableName = match[2];
52
+ const operation = match[3].toLowerCase();
53
+ const policyStart = match.index;
54
+
55
+ // Check policy naming: rbac_{operation}_{table_name}_{scope}
56
+ const expectedPattern = new RegExp(`^rbac_${operation}_${tableName}(?:_\\w+)?$`, 'i');
57
+ if (!expectedPattern.test(policyName)) {
58
+ issues.push({
59
+ type: 'rlsPolicy',
60
+ file: relativePath,
61
+ line: getLineNumber(content, policyStart),
62
+ message: `RLS policy '${policyName}' does not follow naming convention. Should be 'rbac_${operation}_${tableName}' or 'rbac_${operation}_${tableName}_scope'.`,
63
+ code: getCodeSnippet(content, policyStart, 0, 100),
64
+ severity: 'error',
65
+ fix: `Rename policy to follow pattern: rbac_${operation}_${tableName}`,
66
+ });
67
+ }
68
+
69
+ // Find the USING/WITH CHECK clause
70
+ const policyEnd = content.indexOf(';', policyStart);
71
+ if (policyEnd === -1) continue;
72
+
73
+ const policyBody = content.substring(policyStart, policyEnd);
74
+
75
+ // Check for inline auth.uid() calls (performance issue)
76
+ const authUidPattern = /\bauth\.uid\s*\(/gi;
77
+ if (authUidPattern.test(policyBody) && !isInCommentOrStringSQL(content, content.indexOf('auth.uid', policyStart))) {
78
+ issues.push({
79
+ type: 'rlsPolicy',
80
+ file: relativePath,
81
+ line: getLineNumber(content, policyStart),
82
+ message: `RLS policy '${policyName}' contains inline auth.uid() call. Must use helper function instead for performance.`,
83
+ code: getCodeSnippet(content, policyStart, 0, 200),
84
+ severity: 'error',
85
+ fix: 'Replace auth.uid() with helper function like get_effective_user_id(). Helper functions must be STABLE SECURITY DEFINER.',
86
+ });
87
+ }
88
+
89
+ // Check for subqueries in USING/WITH CHECK (performance issue)
90
+ const subqueryPattern = /(?:USING|WITH\s+CHECK)\s*\([^)]*(?:SELECT\s+[^)]+FROM[^)]+WHERE[^)]*)\)/gi;
91
+ if (subqueryPattern.test(policyBody)) {
92
+ issues.push({
93
+ type: 'rlsPolicy',
94
+ file: relativePath,
95
+ line: getLineNumber(content, policyStart),
96
+ message: `RLS policy '${policyName}' contains subquery. Must use helper functions instead for performance.`,
97
+ code: getCodeSnippet(content, policyStart, 0, 200),
98
+ severity: 'error',
99
+ fix: 'Replace subquery with helper function. Helper functions must be STABLE SECURITY DEFINER SET search_path TO public.',
100
+ });
101
+ }
102
+
103
+ // Check for inline current_setting calls (performance issue)
104
+ const currentSettingPattern = /\bcurrent_setting\s*\(/gi;
105
+ if (currentSettingPattern.test(policyBody) && !isInCommentOrStringSQL(content, content.indexOf('current_setting', policyStart))) {
106
+ issues.push({
107
+ type: 'rlsPolicy',
108
+ file: relativePath,
109
+ line: getLineNumber(content, policyStart),
110
+ message: `RLS policy '${policyName}' contains inline current_setting() call. Must use helper function instead for performance.`,
111
+ code: getCodeSnippet(content, policyStart, 0, 200),
112
+ severity: 'error',
113
+ fix: 'Replace current_setting() with helper function. Helper functions must be STABLE SECURITY DEFINER.',
114
+ });
115
+ }
116
+
117
+ // Check for is_super_admin() without parameter (security risk)
118
+ const isSuperAdminWithoutParamPattern = /\bis_super_admin\s*\(\s*\)/gi;
119
+ if (isSuperAdminWithoutParamPattern.test(policyBody) && !isInCommentOrStringSQL(content, content.indexOf('is_super_admin', policyStart))) {
120
+ issues.push({
121
+ type: 'rlsPolicy',
122
+ file: relativePath,
123
+ line: getLineNumber(content, policyStart),
124
+ message: `RLS policy '${policyName}' uses is_super_admin() without parameter. Must use is_super_admin(safe_get_user_id_for_rls()) to avoid fallback strategy vulnerabilities.`,
125
+ code: getCodeSnippet(content, policyStart, 0, 200),
126
+ severity: 'error',
127
+ fix: 'Replace is_super_admin() with is_super_admin(safe_get_user_id_for_rls()) to require explicit parameter passing.',
128
+ });
129
+ }
130
+
131
+ // Check for missing super-admin checks in authenticated policies
132
+ const isAuthenticatedPolicy = /TO\s+authenticated/i.test(policyBody);
133
+ const hasSuperAdminCheck = /\bis_super_admin\s*\(/i.test(policyBody);
134
+ const isPublicPolicy = /TO\s+(?:public|anon)/i.test(policyBody) || policyName.toLowerCase().includes('public') || policyName.toLowerCase().includes('anon');
135
+
136
+ // Exception: User-scoped policies that only check user_id don't need super-admin
137
+ const isUserScopedOnly = /organisation_id\s+IS\s+NULL/i.test(policyBody) &&
138
+ /get_effective_user_id\s*\(\s*\)\s*=\s*user_id/i.test(policyBody) &&
139
+ !/\bOR\b/i.test(policyBody);
140
+
141
+ // Skip check for public/anonymous policies or service role policies
142
+ if (isAuthenticatedPolicy && !hasSuperAdminCheck && !isPublicPolicy && !policyName.toLowerCase().includes('service')) {
143
+ if (!isUserScopedOnly) {
144
+ issues.push({
145
+ type: 'rlsPolicy',
146
+ file: relativePath,
147
+ line: getLineNumber(content, policyStart),
148
+ message: `RLS policy '${policyName}' for authenticated users is missing super-admin check. All authenticated policies must include is_super_admin(safe_get_user_id_for_rls()) as a bypass.`,
149
+ code: getCodeSnippet(content, policyStart, 0, 200),
150
+ severity: 'error',
151
+ fix: 'Add is_super_admin(safe_get_user_id_for_rls()) check. Pattern: (is_super_admin(safe_get_user_id_for_rls()) OR ...other checks...)',
152
+ });
153
+ }
154
+ }
155
+
156
+ // Check for use of deprecated event access functions when RBAC permissions should be used
157
+ const usesEventAccess = /\bcheck_user_event_access\s*\(/i.test(policyBody);
158
+ const usesEventCreator = /\bcheck_user_is_event_creator\s*\(/i.test(policyBody);
159
+ const usesRBACPermission = /\bcheck_rbac_permission_with_context\s*\(/i.test(policyBody);
160
+
161
+ // Tables that have page permissions and should use RBAC permission checks
162
+ const tablesWithPagePermissions = [
163
+ 'trac_contacts', 'trac_risks', 'trac_journal_posts', 'trac_currency_rates',
164
+ 'trac_accommodation', 'trac_activity', 'trac_transport',
165
+ 'mint_budgets', 'mint_budget_variables',
166
+ 'cake_dish', 'cake_meal', 'cake_item', 'cake_recipe',
167
+ 'medi_profile', 'medi_action_plan'
168
+ ];
169
+
170
+ const hasPagePermissions = tablesWithPagePermissions.some(t =>
171
+ tableName.toLowerCase().includes(t.toLowerCase())
172
+ );
173
+
174
+ if (hasPagePermissions && (usesEventAccess || usesEventCreator) && !usesRBACPermission) {
175
+ issues.push({
176
+ type: 'rlsPolicy',
177
+ file: relativePath,
178
+ line: getLineNumber(content, policyStart),
179
+ message: `RLS policy '${policyName}' uses ${usesEventAccess ? 'check_user_event_access()' : 'check_user_is_event_creator()'} but table '${tableName}' has page permissions. Should use check_rbac_permission_with_context() with page-level permissions instead.`,
180
+ code: getCodeSnippet(content, policyStart, 0, 200),
181
+ severity: 'error',
182
+ fix: `Replace ${usesEventAccess ? 'check_user_event_access(event_id)' : 'check_user_is_event_creator(event_id)'} with check_rbac_permission_with_context('${operation}:page.{page_name}', '{page_name}', organisation_id, event_id::text, get_app_id('{app_name}')). See RBAC compliance standard for page name mapping.`,
183
+ });
184
+ }
185
+
186
+ // Check for missing required field checks in event-scoped tables
187
+ const hasEventIdColumn = /event_id/i.test(policyBody) || tableName.toLowerCase().includes('trac_') ||
188
+ tableName.toLowerCase().includes('mint_') ||
189
+ tableName.toLowerCase().includes('cake_') ||
190
+ tableName.toLowerCase().includes('medi_');
191
+ const hasOrganisationIdColumn = /organisation_id/i.test(policyBody) ||
192
+ !tableName.toLowerCase().includes('rbac_') &&
193
+ !tableName.toLowerCase().includes('core_organisations');
194
+
195
+ const checksEventIdNotNull = /event_id\s+IS\s+NOT\s+NULL/i.test(policyBody);
196
+ const checksOrganisationIdNotNull = /organisation_id\s+IS\s+NOT\s+NULL/i.test(policyBody);
197
+
198
+ // For INSERT policies on event-scoped tables, event_id should be required
199
+ if (operation === 'insert' && hasEventIdColumn && !checksEventIdNotNull) {
200
+ issues.push({
201
+ type: 'rlsPolicy',
202
+ file: relativePath,
203
+ line: getLineNumber(content, policyStart),
204
+ message: `RLS INSERT policy '${policyName}' for event-scoped table '${tableName}' should require event_id IS NOT NULL. Permission checks need event_id to verify event-level roles.`,
205
+ code: getCodeSnippet(content, policyStart, 0, 200),
206
+ severity: 'error',
207
+ fix: 'Add event_id IS NOT NULL check to WITH CHECK clause. Pattern: event_id IS NOT NULL AND ...',
208
+ });
209
+ }
210
+
211
+ // For authenticated policies, organisation_id should typically be checked
212
+ if (isAuthenticatedPolicy && hasOrganisationIdColumn && !checksOrganisationIdNotNull &&
213
+ !isUserScopedOnly && !tableName.toLowerCase().includes('rbac_')) {
214
+ // Exception: Some tables legitimately allow NULL organisation_id (e.g., user profiles)
215
+ const allowsNullOrg = /organisation_id\s+IS\s+NULL/i.test(policyBody) &&
216
+ /get_effective_user_id\s*\(\s*\)\s*=\s*user_id/i.test(policyBody);
217
+
218
+ if (!allowsNullOrg) {
219
+ issues.push({
220
+ type: 'rlsPolicy',
221
+ file: relativePath,
222
+ line: getLineNumber(content, policyStart),
223
+ message: `RLS policy '${policyName}' for table '${tableName}' should check organisation_id IS NOT NULL. Permission checks need organisation_id for proper RBAC context.`,
224
+ code: getCodeSnippet(content, policyStart, 0, 200),
225
+ severity: 'warning',
226
+ fix: 'Add organisation_id IS NOT NULL check. Pattern: organisation_id IS NOT NULL AND ...',
227
+ });
228
+ }
229
+ }
230
+ }
231
+
232
+ // Check helper function definitions for required attributes
233
+ const functionPattern = /CREATE\s+(?:OR\s+REPLACE\s+)?FUNCTION\s+["']?(\w+)["']?\s*\([^)]*\)\s*RETURNS[^;]+LANGUAGE\s+plpgsql[^;]*AS/gi;
234
+ let funcMatch;
235
+ while ((funcMatch = functionPattern.exec(content)) !== null) {
236
+ const funcName = funcMatch[1];
237
+ const funcStart = funcMatch.index;
238
+ const funcEnd = content.indexOf('AS $$', funcStart);
239
+ if (funcEnd === -1) continue;
240
+
241
+ const funcDef = content.substring(funcStart, funcEnd);
242
+
243
+ // Only flag if function looks like it might be used in RLS (has common helper function patterns)
244
+ const isLikelyRLSHelper = /check_|get_|is_/.test(funcName.toLowerCase());
245
+
246
+ // Check for security-critical functions with fallback strategies
247
+ if (funcName.toLowerCase() === 'is_super_admin' || funcName.toLowerCase().includes('super_admin')) {
248
+ const funcBodyStart = content.indexOf('AS $$', funcStart);
249
+ if (funcBodyStart !== -1) {
250
+ const funcBodyEnd = content.indexOf('$$;', funcBodyStart);
251
+ if (funcBodyEnd !== -1) {
252
+ const funcBody = content.substring(funcBodyStart, funcBodyEnd);
253
+
254
+ // Check for DEFAULT NULL parameter (allows fallback strategies)
255
+ const hasDefaultNull = /p_\w+\s+UUID\s+DEFAULT\s+NULL/i.test(funcDef);
256
+
257
+ // Check for multiple fallback patterns in function body
258
+ const hasFallbackPatterns = (
259
+ /IF\s+\w+\s+IS\s+NULL\s+THEN/i.test(funcBody) &&
260
+ /ELSE/i.test(funcBody) &&
261
+ (/\bauth\.uid\s*\(/i.test(funcBody) || /\bcurrent_setting\s*\(/i.test(funcBody))
262
+ );
263
+
264
+ if (hasDefaultNull || hasFallbackPatterns) {
265
+ issues.push({
266
+ type: 'rlsPolicy',
267
+ file: relativePath,
268
+ line: getLineNumber(content, funcStart),
269
+ message: `Security-critical function '${funcName}' uses fallback strategies (DEFAULT NULL parameter or multiple fallback patterns). This is a security risk - functions should require explicit parameters and fail secure.`,
270
+ code: getCodeSnippet(content, funcStart, 0, 300),
271
+ severity: 'error',
272
+ fix: 'Remove DEFAULT NULL parameter and all fallback logic. Function should require explicit parameter and return false if parameter is NULL (fail secure).',
273
+ });
274
+ }
275
+ }
276
+ }
277
+ }
278
+
279
+ if (isLikelyRLSHelper) {
280
+ const hasStable = /\bSTABLE\b/i.test(funcDef);
281
+ const hasSecurityDefiner = /\bSECURITY\s+DEFINER\b/i.test(funcDef);
282
+ const hasSearchPath = /SET\s+search_path\s+TO\s+['"]?public['"]?/i.test(funcDef);
283
+
284
+ if (!hasStable) {
285
+ issues.push({
286
+ type: 'rlsPolicy',
287
+ file: relativePath,
288
+ line: getLineNumber(content, funcStart),
289
+ message: `Helper function '${funcName}' missing STABLE attribute. RLS helper functions must be STABLE for performance.`,
290
+ code: getCodeSnippet(content, funcStart, 0, 150),
291
+ severity: 'error',
292
+ fix: 'Add STABLE attribute to function definition.',
293
+ });
294
+ }
295
+
296
+ if (!hasSecurityDefiner) {
297
+ issues.push({
298
+ type: 'rlsPolicy',
299
+ file: relativePath,
300
+ line: getLineNumber(content, funcStart),
301
+ message: `Helper function '${funcName}' missing SECURITY DEFINER attribute. RLS helper functions must be SECURITY DEFINER to bypass RLS recursion.`,
302
+ code: getCodeSnippet(content, funcStart, 0, 150),
303
+ severity: 'error',
304
+ fix: 'Add SECURITY DEFINER attribute to function definition.',
305
+ });
306
+ }
307
+
308
+ if (!hasSearchPath) {
309
+ issues.push({
310
+ type: 'rlsPolicy',
311
+ file: relativePath,
312
+ line: getLineNumber(content, funcStart),
313
+ message: `Helper function '${funcName}' missing SET search_path TO public. Required to prevent search path injection.`,
314
+ code: getCodeSnippet(content, funcStart, 0, 150),
315
+ severity: 'error',
316
+ fix: 'Add SET search_path TO public to function definition.',
317
+ });
318
+ }
319
+ }
320
+ }
321
+ } catch (error) {
322
+ // Skip files that can't be read
323
+ }
324
+ });
325
+
326
+ return issues;
327
+ }
328
+
329
+ /**
330
+ * Check PagePermissionGuard coverage (all protected pages have guard)
331
+ */
332
+ function checkPagePermissionGuardCoverage(consumingAppPath) {
333
+ const issues = [];
334
+
335
+ const srcDir = path.join(consumingAppPath, 'src');
336
+ if (!directoryExists(srcDir)) {
337
+ return issues;
338
+ }
339
+
340
+ const sourceFiles = findSourceFiles(srcDir);
341
+
342
+ // Helper to check if file is likely a page component
343
+ function isPageComponent(filePath, content) {
344
+ const fileName = path.basename(filePath);
345
+ const dirName = path.dirname(filePath);
346
+ const dirParts = dirName.split(path.sep);
347
+
348
+ // EXCLUDE: Provider components, routing components, shared components
349
+ if (dirParts.some(part => part.toLowerCase() === 'providers' || part.toLowerCase() === 'provider')) {
350
+ return false;
351
+ }
352
+ if (/Route(s)?\.(tsx?|jsx?)$/i.test(fileName)) {
353
+ return false;
354
+ }
355
+
356
+ // INCLUDE: Files in pages/ directory
357
+ if (dirParts.some(part => part.toLowerCase() === 'pages')) {
358
+ return true;
359
+ }
360
+
361
+ // INCLUDE: Files matching *Page.tsx pattern
362
+ if (/Page\.(tsx?|jsx?)$/i.test(fileName)) {
363
+ return true;
364
+ }
365
+
366
+ return false;
367
+ }
368
+
369
+ sourceFiles.forEach(filePath => {
370
+ const content = readFileSafe(filePath);
371
+ if (!content) {
372
+ return;
373
+ }
374
+
375
+ if (!isPageComponent(filePath, content)) {
376
+ return;
377
+ }
378
+
379
+ const relativePath = getRelativePath(filePath, consumingAppPath);
380
+ const fileName = path.basename(filePath, path.extname(filePath));
381
+
382
+ // Exclude public/error pages that don't need RBAC protection
383
+ // NotFound, 404, Error, Unauthorized, Forbidden, AccessDenied pages are public
384
+ const isPublicPage = /NotFound|not.*found|404|Error|Unauthorized|Forbidden|AccessDenied/i.test(fileName) ||
385
+ /public|error|unauthorized|forbidden|access.*denied/i.test(relativePath);
386
+
387
+ if (isPublicPage) {
388
+ return; // Skip public/error pages - they don't need PagePermissionGuard
389
+ }
390
+
391
+ // Check if PagePermissionGuard is used
392
+ const hasPagePermissionGuard = /<PagePermissionGuard/.test(content) ||
393
+ /PagePermissionGuard\s*</.test(content);
394
+
395
+ // Check if RBAC hooks are imported (indicates this should be protected)
396
+ const hasRBACHooks = importsFromPaceCore(content, 'useCan') ||
397
+ importsFromPaceCore(content, 'useResourcePermissions') ||
398
+ importsFromPaceCore(content, 'usePermissions') ||
399
+ importsFromPaceCore(content, 'useRBAC');
400
+
401
+ // Check if component returns JSX (likely a page)
402
+ const returnsJSX = /return\s*\(/.test(content) || /return\s+</.test(content);
403
+
404
+ if (returnsJSX && !hasPagePermissionGuard) {
405
+ if (hasRBACHooks) {
406
+ // Definitely should be protected
407
+ issues.push({
408
+ type: 'rbacPageGuard',
409
+ file: relativePath,
410
+ line: 1,
411
+ message: 'Page component missing PagePermissionGuard wrapper. Pages using RBAC hooks must be protected.',
412
+ severity: 'error',
413
+ fix: 'Wrap page content with <PagePermissionGuard pageName="page-name" operation="read">',
414
+ });
415
+ } else {
416
+ // Might be a public page, but flag for review
417
+ issues.push({
418
+ type: 'rbacPageGuard',
419
+ file: relativePath,
420
+ line: 1,
421
+ message: 'Page component does not use PagePermissionGuard. Verify if this page should be protected.',
422
+ severity: 'warning',
423
+ fix: 'If page should be protected, wrap with <PagePermissionGuard pageName="page-name" operation="read">',
424
+ });
425
+ }
426
+ }
427
+
428
+ // Check if PagePermissionGuard is used incorrectly (missing required props)
429
+ if (hasPagePermissionGuard) {
430
+ const pageGuardPattern = /<PagePermissionGuard[^>]*>/g;
431
+ let match;
432
+ while ((match = pageGuardPattern.exec(content)) !== null) {
433
+ if (isInCommentOrString(content, match.index)) {
434
+ continue;
435
+ }
436
+
437
+ const guardProps = match[0];
438
+ const hasPageName = /pageName\s*=/.test(guardProps);
439
+ const hasOperation = /operation\s*=/.test(guardProps);
440
+
441
+ if (!hasPageName || !hasOperation) {
442
+ issues.push({
443
+ type: 'rbacPageGuard',
444
+ file: relativePath,
445
+ line: getLineNumber(content, match.index),
446
+ message: 'PagePermissionGuard missing required props (pageName or operation)',
447
+ code: guardProps,
448
+ severity: 'error',
449
+ fix: 'Add required props: <PagePermissionGuard pageName="page-name" operation="read">',
450
+ });
451
+ }
452
+ }
453
+ }
454
+ });
455
+
456
+ return issues;
457
+ }
458
+
459
+ /**
460
+ * Check Edge Functions RBAC setup
461
+ */
462
+ function checkEdgeFunctionsRBAC(consumingAppPath) {
463
+ const issues = [];
464
+
465
+ const edgeFunctionsDir = path.join(consumingAppPath, 'supabase', 'functions');
466
+ if (!directoryExists(edgeFunctionsDir)) {
467
+ return issues; // No edge functions, skip
468
+ }
469
+
470
+ // Find all edge function files
471
+ function findEdgeFunctionFiles(dir) {
472
+ const files = [];
473
+ if (!fs.existsSync(dir)) return files;
474
+
475
+ const entries = fs.readdirSync(dir);
476
+ entries.forEach(entry => {
477
+ const entryPath = path.join(dir, entry);
478
+ const stat = fs.statSync(entryPath);
479
+
480
+ if (stat.isDirectory()) {
481
+ // Look for index.ts or index.js in function directory
482
+ const indexFiles = ['index.ts', 'index.js', 'index.tsx', 'index.jsx'];
483
+ indexFiles.forEach(indexFile => {
484
+ const indexPath = path.join(entryPath, indexFile);
485
+ if (fs.existsSync(indexPath)) {
486
+ files.push(indexPath);
487
+ }
488
+ });
489
+ }
490
+ });
491
+
492
+ return files;
493
+ }
494
+
495
+ const edgeFunctionFiles = findEdgeFunctionFiles(edgeFunctionsDir);
496
+
497
+ edgeFunctionFiles.forEach(filePath => {
498
+ const content = readFileSafe(filePath);
499
+ if (!content) {
500
+ return;
501
+ }
502
+
503
+ const relativePath = getRelativePath(filePath, consumingAppPath);
504
+
505
+ // Check for setupRBAC import
506
+ const hasSetupRBAC = /setupRBAC|from\s+['"]@jmruthers\/pace-core\/rbac['"]/.test(content);
507
+
508
+ // Check for isPermitted usage
509
+ const hasIsPermitted = /\bisPermitted\s*\(/.test(content);
510
+
511
+ // If function uses RBAC but doesn't call setupRBAC
512
+ if (hasIsPermitted && !hasSetupRBAC) {
513
+ issues.push({
514
+ type: 'edgeFunctionRBAC',
515
+ file: relativePath,
516
+ line: 1,
517
+ message: 'Edge function uses isPermitted() but does not call setupRBAC(). Must call setupRBAC() before using RBAC functions.',
518
+ severity: 'error',
519
+ fix: 'Add: import { setupRBAC, isPermitted } from \'@jmruthers/pace-core/rbac\'; and call setupRBAC() at the start of the handler.',
520
+ });
521
+ }
522
+ });
523
+
524
+ return issues;
525
+ }
526
+
527
+ /**
528
+ * Run audit for Standard 6: Security & RBAC
529
+ * @param {string} consumingAppPath - Path to consuming app
530
+ * @returns {object} - Audit results with issues array
531
+ */
532
+ function runStandard6Audit(consumingAppPath) {
533
+ const issues = [];
534
+
535
+ try {
536
+ issues.push(...checkRLSPolicies(consumingAppPath));
537
+ issues.push(...checkPagePermissionGuardCoverage(consumingAppPath));
538
+ issues.push(...checkEdgeFunctionsRBAC(consumingAppPath));
539
+ } catch (error) {
540
+ return {
541
+ standard: '06-security-rbac',
542
+ issues: [],
543
+ error: error.message,
544
+ };
545
+ }
546
+
547
+ return {
548
+ standard: '06-security-rbac',
549
+ issues,
550
+ error: null,
551
+ };
552
+ }
553
+
554
+ module.exports = { runStandard6Audit };