permdock 0.3.1 → 0.5.0
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/README.md +37 -35
- package/dist/{openapi-schema--ARjyfQr.js → 2020-C9VN-x8c.js} +5 -132
- package/dist/a2a/index.d.ts +8 -6
- package/dist/a2a/index.js +21 -31
- package/dist/{adapter-context-mlWsVGGg.js → adapter-context-CRhqyzCk.js} +1 -1
- package/dist/adoption-scan-B4R5fnMU.js +107 -0
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.js +1 -0
- package/dist/ai-sdk/index.d.ts +18 -23
- package/dist/ai-sdk/index.js +38 -21
- package/dist/app-data-MuyzVqX8.js +60 -0
- package/dist/approval-header-CJACtHkv.js +23 -0
- package/dist/approval-prompt-Dg5LeAcT.js +62 -0
- package/dist/approval-prompt-Djo_PyZc.d.ts +57 -0
- package/dist/approvals/index.d.ts +5 -3
- package/dist/approvals/index.js +8 -5
- package/dist/approvals-DJ6Yd5z1.js +995 -0
- package/dist/{approvers-DT4AVyIg.js → approvers-CqPOLD-o.js} +1 -1
- package/dist/arazzo-B6lebmiQ.js +36 -0
- package/dist/{arazzo-BAgw9ap6.js → arazzo-BWhNF-k0.js} +24 -17
- package/dist/args-IIolxxKA.js +197 -0
- package/dist/astro/index.d.ts +43 -0
- package/dist/astro/index.js +27 -0
- package/dist/audience-Dg8XsRaO.js +55 -0
- package/dist/auth-DRLEizbL.js +178 -0
- package/dist/authzen/index.d.ts +26 -6
- package/dist/authzen/index.js +228 -75
- package/dist/automation-BMZPIVUM.d.ts +114 -0
- package/dist/automation-DVjOckjV.js +157 -0
- package/dist/better-auth/index.d.ts +8 -6
- package/dist/better-auth/index.js +11 -23
- package/dist/better-supabase/index.d.ts +438 -86
- package/dist/better-supabase/index.js +1027 -184
- package/dist/bind--9EFVYWF.d.ts +38 -0
- package/dist/{bind-CuzGytRf.js → bind-CZzhx-Vj.js} +22 -10
- package/dist/body-CH5of8Ne.js +10 -0
- package/dist/body-text-QcXok_SI.js +52 -0
- package/dist/build-instance-BMnAudHn.js +52 -0
- package/dist/{canonical-json-DemiK4Vp.js → canonical-json-BC8_nMTw.js} +6 -6
- package/dist/{capability-2kYTMWDv.d.ts → capability-BSslw1QV.d.ts} +44 -25
- package/dist/{capability-4qPdO9gk.js → capability-N1K9IpqS.js} +69 -42
- package/dist/casbin-Cr7RLtA3.js +30 -0
- package/dist/casbin-Dyu2gnUD.js +234 -0
- package/dist/casl-64gpT-8x.js +24 -0
- package/dist/casl-DjEDhTCP.js +299 -0
- package/dist/catalog/index.d.ts +74 -2
- package/dist/catalog/index.js +51 -2
- package/dist/catalog-BECMPrwc.js +100 -0
- package/dist/catalog-DjhMYYCq.js +1 -0
- package/dist/catalog-R_A__RsH.js +52 -0
- package/dist/{catalog-doc-DdGm82XT.js → catalog-doc-C9wjsfNY.js} +54 -25
- package/dist/catalog-fingerprint-CCP0-yQS.js +153 -0
- package/dist/chat/index.d.ts +2 -0
- package/dist/chat/index.js +224 -0
- package/dist/chat-sdk/index.d.ts +87 -0
- package/dist/chat-sdk/index.js +197 -0
- package/dist/claims-map-7oQ3ue4X.js +13 -0
- package/dist/claims-map-Ca-QX8C6.d.ts +32 -0
- package/dist/claude-agent/index.d.ts +7 -14
- package/dist/claude-agent/index.js +26 -30
- package/dist/clerk/index.d.ts +9 -8
- package/dist/clerk/index.js +15 -45
- package/dist/cli/bin.js +36 -17
- package/dist/cli/index.d.ts +20 -6
- package/dist/cli/index.js +164 -4
- package/dist/cloud/index.d.ts +102 -63
- package/dist/cloud/index.js +240 -347
- package/dist/cloud-CIoHNevm.js +87 -0
- package/dist/codemod-Bmj9dWMH.js +37 -0
- package/dist/codemod-Cxvvc70T.js +2084 -0
- package/dist/{collect-DSTE3ml9.js → collect-CrZJJnEF.js} +79 -17
- package/dist/collect-DloHbDVa.js +55 -0
- package/dist/collect-FlXJlhus.js +1 -0
- package/dist/command-L8EstFNm.js +6 -0
- package/dist/{compact-y6vfu2_f.js → compact-CAf557ZB.js} +11 -1
- package/dist/compile/index.d.ts +1 -1
- package/dist/compile/index.js +1 -2
- package/dist/{compile-Ba4blROR.js → compile-CMqMx_IN.js} +13 -9
- package/dist/{compile-BkRyBDBw.d.ts → compile-Ckm2HqBZ.d.ts} +5 -3
- package/dist/completion-BqhRBJD8.js +143 -0
- package/dist/config-B46rm9sc.js +26 -0
- package/dist/{config-BJiM-xAm.js → config-bs_kZeYq.js} +15 -10
- package/dist/{config-report-CdCgbRnV.js → config-report-DUgj62Ai.js} +17 -8
- package/dist/{connection-CU8MQxRi.js → connection-DjhIJSs2.js} +8 -6
- package/dist/constants-DcJABbLW.js +20 -0
- package/dist/{context-Bcy85rGi.js → context-bbFHR-0D.js} +16 -5
- package/dist/convex/index.d.ts +11 -10
- package/dist/convex/index.js +18 -18
- package/dist/create-0VZ7Pdiu.d.ts +107 -0
- package/dist/create-BDS7wc3y.d.ts +138 -0
- package/dist/create-BFfm17UA.d.ts +110 -0
- package/dist/create-BWRSXgOF.js +403 -0
- package/dist/create-C3b4B5eF.js +130 -0
- package/dist/create-DnrmLnLW.js +323 -0
- package/dist/{credential-8P81ff4u.js → credential-DM2um3ha.js} +153 -32
- package/dist/credentials-DPyHmYz5.js +74 -0
- package/dist/deciding-columns-Sq12mEA6.js +123 -0
- package/dist/delegation-DaXVdDhM.js +286 -0
- package/dist/delegation-input-FTxMK3ji.js +19 -0
- package/dist/delivery/index.d.ts +5 -0
- package/dist/delivery/index.js +5 -0
- package/dist/delivery-DCAgNyCn.js +499 -0
- package/dist/delivery-event-xX4obB8F.js +40 -0
- package/dist/denied-text-D8jDHgsl.d.ts +19 -0
- package/dist/{describe-DMYiCjJV.d.ts → describe-BZUsixiL.d.ts} +11 -2
- package/dist/{describe-B_gVZEVi.js → describe-BybMRY7A.js} +10 -5
- package/dist/device-BARQ8eYG.js +193 -0
- package/dist/diff-CxZo9pTq.js +37 -0
- package/dist/{diff-2VaeChzX.js → diff-DCePiN6M.js} +61 -55
- package/dist/doctor-CxiwSfqH.js +44 -0
- package/dist/doctor-DFjUxf2f.js +2361 -0
- package/dist/drizzle/index.d.ts +5 -3
- package/dist/drizzle/index.js +6 -14
- package/dist/elysia/index.d.ts +16 -13
- package/dist/elysia/index.js +14 -13
- package/dist/env-DJZrPjRi.js +8 -0
- package/dist/errors-BDUwg2qC.js +27 -0
- package/dist/{errors-Cz5zn0mW.js → errors-BKy0EfhN.js} +6 -10
- package/dist/errors-BWXBMaKK.d.ts +11 -0
- package/dist/{errors-DPdqI50v.d.ts → errors-C2PXIv4c.d.ts} +2 -2
- package/dist/errors-CWTY6uih.js +143 -0
- package/dist/evaluate-_R8QkWaf.js +1732 -0
- package/dist/evaluations-16UqqQ6W.d.ts +32 -0
- package/dist/{evaluations-tz6D9A2G.js → evaluations-DZ2CbV5k.js} +181 -32
- package/dist/eve/index.d.ts +12 -16
- package/dist/eve/index.js +23 -29
- package/dist/event-time-CsegxXxB.js +23 -0
- package/dist/expiry-D4_YKRKD.js +52 -0
- package/dist/express/index.d.ts +13 -10
- package/dist/express/index.js +14 -12
- package/dist/fastify/index.d.ts +26 -13
- package/dist/fastify/index.js +17 -36
- package/dist/fetch-adapter-g0ypLkID.js +120 -0
- package/dist/fetch-adapter-qKJBuRqy.d.ts +31 -0
- package/dist/fields-D9tPVUUS.js +203 -0
- package/dist/files-C5ZI27eV.js +124 -0
- package/dist/{files-DWUN9PzI.js → files-D_JIzUrP.js} +12 -3
- package/dist/{fixtures-ht28Cplr.js → fixtures-B7XrLeY7.js} +12 -12
- package/dist/flags-C3DktBDY.js +86 -0
- package/dist/{from-snapshot-CTLijvdm.js → from-snapshot-D2lZt4Dd.js} +78 -65
- package/dist/{generate-CH7ThJ14.js → generate-CNU1pIOo.js} +1 -3
- package/dist/grantee-Cn1HyUsI.js +254 -0
- package/dist/grantee-conditions-CcXf8hMM.js +271 -0
- package/dist/grantee-match-DHArqY82.js +142 -0
- package/dist/h3/index.d.ts +37 -0
- package/dist/h3/index.js +35 -0
- package/dist/headers-BIjfMaoC.js +8 -0
- package/dist/headers-CIbDTUTK.d.ts +7 -0
- package/dist/{helpers-H_KARDVC.js → helpers-DTcZOzhF.js} +47 -39
- package/dist/hono/index.d.ts +12 -9
- package/dist/hono/index.js +14 -13
- package/dist/{hosted-DJQw46hn.js → hosted-BZIAYvon.js} +64 -15
- package/dist/hosted-DBDX0M-P.d.ts +78 -0
- package/dist/{http-SO7qGttf.js → http-BBoKefeS.js} +35 -2
- package/dist/{http-DPuDaChb.d.ts → http-B_LphE5Y.d.ts} +1 -2
- package/dist/http-DXJ37RDA.js +46 -0
- package/dist/{http-BIhmLfCc.js → http-ujKm0JXE.js} +3 -26
- package/dist/{openapi-import-cmwetbzw.js → import-CNV7I2Dw.js} +30 -26
- package/dist/{rls-import-4lLW_pbb.js → import-DMmOG27O.js} +271 -128
- package/dist/index-BcHcPyIo.d.ts +110 -0
- package/dist/index-CaxrMD1A.d.ts +1 -0
- package/dist/index-Chrs5fQ-.d.ts +210 -0
- package/dist/index-CxGUswIC.d.ts +431 -0
- package/dist/index-D8EovfsP.d.ts +91 -0
- package/dist/index-DOVf7RJv.d.ts +900 -0
- package/dist/{index-C8z4RjQV.d.ts → index-SGdIQyzc.d.ts} +34 -16
- package/dist/index.d.ts +20 -14
- package/dist/index.js +33 -23
- package/dist/init-DeMYsnYJ.js +96 -0
- package/dist/init-GG6Jh8HD.js +95 -0
- package/dist/{instance-options-jARdwfPN.d.ts → instance-options-Omfd793B.d.ts} +2 -2
- package/dist/instance-snapshot-Cxq4ygFc.js +600 -0
- package/dist/instant-BluqDvyS.js +19 -0
- package/dist/internals-Dk8A8fX3.js +17 -0
- package/dist/{json-schema-BsAflUGW.js → json-schema-B-vAwlde.js} +46 -9
- package/dist/json-schema-CN_iLFH2.d.ts +40 -0
- package/dist/jwt/index.d.ts +18 -11
- package/dist/jwt/index.js +166 -145
- package/dist/{kernel-_RRHmnMY.js → kernel-5JatXyND.js} +120 -43
- package/dist/kysely/index.d.ts +5 -3
- package/dist/kysely/index.js +6 -14
- package/dist/{live-options-H2eG8dfJ.js → live-options-BaAFCIiu.js} +16 -3
- package/dist/load-BxEtwlBS.js +1 -0
- package/dist/{load-DhWEB9P1.js → load-DFS_ry0W.js} +31 -7
- package/dist/{load-jose-BL6LH4bL.js → load-jose-DZ4dnjri.js} +1 -4
- package/dist/login-Dfe5RlYk.js +68 -0
- package/dist/login-imhuwvn3.js +254 -0
- package/dist/manifest-C8IzW3Do.js +42 -0
- package/dist/manifest-CtKR3GXL.js +370 -0
- package/dist/manifest-json-CAGzls-C.js +9 -0
- package/dist/{manifest-uDS9y5de.d.ts → manifest-mx5ghSFM.d.ts} +9 -2
- package/dist/manifest-schema-C0kK_8V0.js +399 -0
- package/dist/{map-claims-Z4QZOiFF.js → map-claims-D3oRmTk0.js} +19 -25
- package/dist/{map-error-pgUWNNtG.js → map-error-TCAdw-eW.js} +5 -5
- package/dist/{markers-B0hYLvMD.js → markers-C6joDI3o.js} +8 -3
- package/dist/mcp/index.d.ts +36 -9
- package/dist/mcp/index.js +476 -448
- package/dist/{rls-migrate-CN4TlJTO.js → migrate-BShP7Vf4.js} +119 -20
- package/dist/nest/index.d.ts +12 -9
- package/dist/nest/index.js +20 -20
- package/dist/next/index.d.ts +40 -20
- package/dist/next/index.js +37 -39
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +2 -2
- package/dist/node/index.d.ts +10 -10
- package/dist/node/index.js +7 -9
- package/dist/ocsf-BFp-PZZA.js +126 -0
- package/dist/openai/index.d.ts +9 -16
- package/dist/openai/index.js +18 -25
- package/dist/openapi/index.d.ts +3 -3
- package/dist/openapi/index.js +1 -1
- package/dist/{openapi-BqRBvAng.js → openapi-B7HZ0f-r.js} +9 -12
- package/dist/{openapi-CqqEbHsL.js → openapi-DTaEmTSW.js} +23 -26
- package/dist/openapi-ahr8rHu3.js +138 -0
- package/dist/operation-findings-DgATDpvh.js +36 -0
- package/dist/operations-CxybZErY.d.ts +59 -0
- package/dist/orpc/index.d.ts +13 -10
- package/dist/orpc/index.js +23 -20
- package/dist/otel/index.d.ts +3 -2
- package/dist/otel/index.js +53 -27
- package/dist/output-Dyw8fyPF.js +88 -0
- package/dist/output-files-B3IZJksC.js +1 -0
- package/dist/output-files-DhRBBE4n.js +138 -0
- package/dist/{rls-fields-CZOMlwHl.js → ownership-BatFgAA4.js} +2393 -2349
- package/dist/{package-root-zGkxO3oN.js → package-root-Dk_ETdkp.js} +4 -3
- package/dist/{parse-BuyjxhZV.js → parse-Cxq0WxrA.js} +3 -3
- package/dist/{parse-local-manifest-BrMozJCo.js → parse-local-manifest-CVSs6J9I.js} +2 -4
- package/dist/{parse-local-manifest-JLnaBH0S.d.ts → parse-local-manifest-DgqtruPn.d.ts} +1 -1
- package/dist/parse-request-D_tUXG6M.js +26 -0
- package/dist/paths-DXSHAMIa.js +42 -0
- package/dist/pdp/index.d.ts +7 -3
- package/dist/pdp/index.js +47 -29
- package/dist/{peer-BOr_kJE1.js → peer-C8swJ2GH.js} +23 -4
- package/dist/peer-CRvC7Hg1.js +1 -0
- package/dist/permdock-B9JxkBwC.js +868 -0
- package/dist/permdock-D7eeLJER.d.ts +502 -0
- package/dist/permission-registry-Br4jSNVi.js +385 -0
- package/dist/permissions-B-wCP5ZC.js +30 -0
- package/dist/{permissions-RJrovw98.js → permissions-CZKiUfFM.js} +4 -3
- package/dist/{permissions-CDgvKG5L.d.ts → permissions-oEWfl-kl.d.ts} +1 -2
- package/dist/policies-CO1oOymN.js +295 -0
- package/dist/{policy-D2W7uv19.d.ts → policy-Czo4n3Hs.d.ts} +2 -2
- package/dist/policy-DLZJ5gAp.js +399 -0
- package/dist/policy-from-catalog-DzhEc3Y9.js +450 -0
- package/dist/policy-module-CTlwMvLI.js +89 -0
- package/dist/{policy-IB6yxpC3.d.ts → policy-types-DzwivBgR.d.ts} +939 -1057
- package/dist/postgrest-CW0IqC-U.js +566 -0
- package/dist/postgrest-NUqZT-RB.d.ts +100 -0
- package/dist/powersync-BHfuehf3.js +62 -0
- package/dist/powersync-CbzkqL_M.js +1 -0
- package/dist/{powersync-Dv1_aWF7.js → powersync-bYUDLOAO.js} +30 -32
- package/dist/preset/index.d.ts +146 -0
- package/dist/preset/index.js +1 -0
- package/dist/preset-DZdU0tne.js +1768 -0
- package/dist/principal-source-pHneukrx.js +103 -0
- package/dist/prisma/index.d.ts +6 -3
- package/dist/prisma/index.js +6 -12
- package/dist/{problem-B43ztKIm.js → problem-CTviyH5L.js} +18 -27
- package/dist/{problem-details-DX075l9V.d.ts → problem-details-DXlt-vks.d.ts} +1 -1
- package/dist/{problem-details-_AMOYz-w.js → problem-details-cn5X30gZ.js} +45 -42
- package/dist/problem-types-CJ2325SZ.js +5 -0
- package/dist/{prompt-CXYhLfsS.js → prompt-DfZLJLIn.js} +2 -2
- package/dist/protected-DEPHc2xV.d.ts +38 -0
- package/dist/{protected-utU-SLuy.js → protected-DfjY5mLA.js} +37 -8
- package/dist/{provider-CSQd7m92.js → provider-CC-u3bYP.js} +23 -10
- package/dist/{provider-DZY281jO.d.ts → provider-DMVt6yYn.d.ts} +1 -1
- package/dist/{provider-store-Cfbvo4DE.js → provider-store-B5Yrkhzr.js} +6 -3
- package/dist/pull-BgIfno6w.js +256 -0
- package/dist/pull-ByOks_Tg.js +1 -0
- package/dist/push-CmFVBOeI.js +116 -0
- package/dist/pushed-policy-BImMTTIM.d.ts +57 -0
- package/dist/pushed-policy-DobP7AHI.js +238 -0
- package/dist/react/index.d.ts +8 -8
- package/dist/react/index.js +6 -6
- package/dist/react/provider-client.d.ts +1 -1
- package/dist/react/provider-client.js +1 -2
- package/dist/react-native/index.d.ts +24 -63
- package/dist/react-native/index.js +45 -27
- package/dist/{refs-KYb4ntaz.js → refs-K6eWUJ0H.js} +1 -1
- package/dist/relation-walk-3OyDBF0S.js +186 -0
- package/dist/relations-BnCWnJGI.js +163 -0
- package/dist/renames-CGj7YwcQ.js +175 -0
- package/dist/{replay-CYyiLiwO.d.ts → replay-D7iKcLFe.d.ts} +1 -1
- package/dist/{replay-BsOyTrdV.js → replay-Du1tJjG7.js} +2 -1
- package/dist/request-context-BTRTG7OT.js +71 -0
- package/dist/request-context-C2_1lchh.d.ts +5 -0
- package/dist/request-schema-CMreVuFM.js +148 -0
- package/dist/resend/index.d.ts +126 -0
- package/dist/resend/index.js +379 -0
- package/dist/resource-relations-D_jw0BFx.js +243 -0
- package/dist/retire-CALjIQ7e.js +240 -0
- package/dist/{revocations-Cy06JNx2.d.ts → revocations-R07lFBnX.d.ts} +2 -0
- package/dist/rls-BA8an5Ap.js +336 -0
- package/dist/{rls-DiinlRML.js → rls-j6t43t7n.js} +1066 -1068
- package/dist/role-builder-CXbis5-X.js +623 -0
- package/dist/{rpc-DL9Sqvb1.js → rpc-aPyNi6tA.js} +18 -8
- package/dist/run-CNsApDpd.js +1 -0
- package/dist/run-DOfMtc9V.js +723 -0
- package/dist/run-ticket-BjhTOi6u.d.ts +124 -0
- package/dist/run-ticket-sxFI6LAk.js +337 -0
- package/dist/{runtime-CB8gQFvS.js → runtime-D3VTAiCA.js} +1 -1
- package/dist/{saas-DhpJjnBA.js → saas-FO-Q8oj0.js} +18 -15
- package/dist/scan-BOI5tJ-6.js +29 -0
- package/dist/{schema-D3MnDMxa.js → schema-B4v0Qrac.js} +106 -10
- package/dist/schema-yLuBWWsh.js +130 -0
- package/dist/scim/index.d.ts +2 -2
- package/dist/scim/index.js +1 -2
- package/dist/{scim-BFGBBAqR.js → scim-ClHtpyV3.js} +213 -87
- package/dist/{scopes-CVdPrWN-.js → scopes-CUPSjo9q.js} +20 -7
- package/dist/server/index.d.ts +13 -134
- package/dist/server/index.js +13 -10
- package/dist/server-DqCT4CgZ.js +453 -0
- package/dist/{create-B1d519XK.d.ts → server-types-BLd4MnBX.d.ts} +89 -70
- package/dist/{sha256-BO0swRXL.js → sha256-D9ihqmvd.js} +8 -1
- package/dist/shared-CD11nBbC.js +304 -0
- package/dist/{shared-DRu8VFVM.js → shared-DvvFzYXe.js} +8 -9
- package/dist/signals-D3NcTKUS.js +32 -0
- package/dist/sink-BEZSlMS_.js +957 -0
- package/dist/sink-Bj_lDUDq.d.ts +225 -0
- package/dist/{skills-Biq5uup3.js → skills-B6lVdD_W.js} +16 -8
- package/dist/skills-CTYwkl44.js +51 -0
- package/dist/snapshot-CXUWfsNy.js +269 -0
- package/dist/{snapshot-cache-D6jLelln.js → snapshot-cache-DZHQ0KF6.js} +11 -5
- package/dist/{snapshot-cache-B-LxUahj.d.ts → snapshot-cache-DqK9eDmM.d.ts} +7 -5
- package/dist/solid/index.d.ts +24 -25
- package/dist/solid/index.js +41 -11
- package/dist/solid-start/index.d.ts +52 -0
- package/dist/solid-start/index.js +49 -0
- package/dist/{sources-BdOYLw9j.d.ts → sources-BV9j0DeZ.d.ts} +11 -13
- package/dist/{sources-4p0-4xQm.js → sources-vs5dGOsS.js} +147 -142
- package/dist/sql-B5T1IL83.js +55 -0
- package/dist/src-DLfUWFAI.js +1851 -0
- package/dist/ssf/index.d.ts +4 -4
- package/dist/ssf/index.js +440 -106
- package/dist/standard-webhooks-6lg8v_is.d.ts +88 -0
- package/dist/standard-webhooks-DgFFD-Ga.js +228 -0
- package/dist/storage-C2bWdvJH.js +132 -0
- package/dist/{store-DMAWwAJV.js → store-4u_hxjWa.js} +42 -55
- package/dist/{store-options-ByhZq1jV.js → store-options-BqEakYRa.js} +38 -24
- package/dist/{stores-BT2pSCub.js → stores-BbsD4fAR.js} +7 -3
- package/dist/stores-ClZUgeoP.d.ts +30 -0
- package/dist/{stream-D1RXubw2.d.ts → stream-7-xmnf3U.d.ts} +2 -2
- package/dist/{stream-DDpvynSB.js → stream-CvdUS9V1.js} +10 -2
- package/dist/style-DiKWnAvn.js +1 -0
- package/dist/{style-CTm1AXDT.js → style-Uao76wO7.js} +3 -2
- package/dist/subject-BGoM5o8B.js +17 -0
- package/dist/{subject-settings-BwBmCdTR.js → subject-settings-CkEwrw3W.js} +23 -5
- package/dist/supabase/index.d.ts +23 -106
- package/dist/supabase/index.js +5 -4
- package/dist/supabase/middleware.d.ts +13 -6
- package/dist/supabase/middleware.js +16 -11
- package/dist/supabase-9pqI57pW.js +92 -0
- package/dist/{supabase-C0qESOa-.js → supabase-Dxlp8A94.js} +124 -247
- package/dist/supabase-hook-CXcGpHqq.js +1 -0
- package/dist/{supabase-hook-ntETYCQu.js → supabase-hook-DdDQhMlw.js} +1659 -819
- package/dist/{supautils-u8jXTGrt.js → supautils-B6HYL9eL.js} +2 -2
- package/dist/support-session-C6xJQYut.js +158 -0
- package/dist/svelte/Protected.svelte +11 -4
- package/dist/svelte/index.d.ts +7 -7
- package/dist/svelte/index.js +26 -12
- package/dist/svelte/runtime.d.ts +10 -3
- package/dist/svelte/runtime.js +4 -3
- package/dist/svelte/source.d.ts +7 -7
- package/dist/svelte/source.js +5 -5
- package/dist/sveltekit/index.d.ts +51 -0
- package/dist/sveltekit/index.js +27 -0
- package/dist/tanstack-start/index.d.ts +51 -0
- package/dist/tanstack-start/index.js +40 -0
- package/dist/target-Bw37TFNA.js +51 -0
- package/dist/{validity-uOp8UpYn.js → tenancy-DN2QAx9z.js} +6 -42
- package/dist/terminal/index.d.ts +11 -9
- package/dist/terminal/index.js +36 -316
- package/dist/testing/index.d.ts +391 -106
- package/dist/testing/index.js +4574 -1286
- package/dist/testing/saas/index.d.ts +9 -8
- package/dist/testing/saas/index.js +2 -2
- package/dist/testing/saas/permissions.d.ts +1 -1
- package/dist/testing/saas/permissions.js +1 -2
- package/dist/text-BMFRfBqc.js +8 -0
- package/dist/{text-diff-BdkkYSbi.js → text-diff-BQcUapOb.js} +1 -1
- package/dist/thenable-yD7SabqG.js +31 -0
- package/dist/time-DkWjdL98.js +71 -0
- package/dist/{token-CIWxJOCh.js → token-BLZcjQgt.js} +15 -6
- package/dist/tool-refusal-CMLN5xhn.js +41 -0
- package/dist/trpc/index.d.ts +12 -9
- package/dist/trpc/index.js +18 -17
- package/dist/{types-DbjRN55U.d.ts → types-5Ut_pbKy.d.ts} +141 -13
- package/dist/types-BNORmDM8.d.ts +172 -0
- package/dist/types-BjV-fqcA.d.ts +57 -0
- package/dist/{types-QCuYJh4q.d.ts → types-BqAKcRNW.d.ts} +2 -1
- package/dist/types-C8-KNsFf.d.ts +107 -0
- package/dist/{types-aqOHTHcp.d.ts → types-CCpc2Dcv.d.ts} +77 -17
- package/dist/{types-Dnemwd77.d.ts → types-CZTnPFzM.d.ts} +50 -11
- package/dist/{types-C97IskBw.d.ts → types-CdlxsYQh.d.ts} +23 -11
- package/dist/{types-DxiCGmmd.d.ts → types-ClZaWzfb.d.ts} +9 -6
- package/dist/types-DX0LaKTb.d.ts +157 -0
- package/dist/types-DiQjupG2.d.ts +332 -0
- package/dist/types-DqzsnlSA.js +67 -0
- package/dist/types-_sHy8BQf.d.ts +65 -0
- package/dist/types-fbZ7JEXr.d.ts +89 -0
- package/dist/types-tIgIeIKJ.d.ts +66 -0
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +2 -2
- package/dist/usage-CHOtwL19.js +1 -0
- package/dist/usage-DHtE8j4E.js +32 -0
- package/dist/{usage-ItS7nLcl.js → usage-T5mXq98v.js} +56 -13
- package/dist/{validation-error-Ba264OaJ.d.ts → validation-error-Bg5Tpluk.d.ts} +1 -1
- package/dist/{validation-error-CnjZ4t92.js → validation-error-ZfUHbKvf.js} +1 -1
- package/dist/validity-CZ7-y0Cj.js +79 -0
- package/dist/{verifier-BxBo6I44.js → verifier-DHuh-okk.js} +68 -21
- package/dist/verify-DbCL9bnB.js +1770 -0
- package/dist/{version-BvacVTZR.js → version-CEbQ5UeM.js} +4 -3
- package/dist/version-DXkYUISx.js +1 -0
- package/dist/{views-Soe7bGSC.js → views-DTIIO-oQ.js} +41 -2
- package/dist/{permissions-DttnqqxC.d.ts → vocabulary-D6lPdb4Z.d.ts} +120 -29
- package/dist/vue/index.d.ts +25 -21
- package/dist/vue/index.js +25 -9
- package/dist/waiter-BGUtGYoU.js +67 -0
- package/dist/waiter-CKy4MQSY.d.ts +36 -0
- package/dist/watch-Cb-NcaUw.js +1 -0
- package/dist/{watch-DVBJ9cBq.js → watch-CszoTJMq.js} +47 -8
- package/dist/webmcp/index.d.ts +2 -2
- package/dist/webmcp/index.js +13 -37
- package/dist/where-scope-Dv-WTP-w.js +306 -0
- package/dist/who-can-D0QoYbEb.js +364 -0
- package/dist/wire-delegation-Cv3W2eaM.js +36 -0
- package/dist/wire-denial-C7PaVYEM.js +27 -0
- package/dist/workflow/index.d.ts +5 -0
- package/dist/workflow/index.js +223 -0
- package/dist/workflow-sdk/index.d.ts +56 -0
- package/dist/workflow-sdk/index.js +78 -0
- package/dist/wrap-Bd1Tejur.d.ts +15 -0
- package/dist/wrap-gX61EtpB.js +27 -0
- package/package.json +140 -41
- package/schemas/access-event-v1.json +118 -0
- package/schemas/approval-request-v1.json +34 -1
- package/schemas/approval-signature-v1.json +94 -0
- package/schemas/automation-event-v1.json +113 -0
- package/schemas/capability-v1.json +84 -0
- package/schemas/catalog-event-v1.json +87 -0
- package/schemas/catalog-v1.json +129 -12
- package/schemas/cli-commands-v1.json +164 -0
- package/schemas/cli-result-v1.json +96 -0
- package/schemas/cloud-api-v1.json +5407 -0
- package/schemas/connector-v1.json +408 -0
- package/schemas/credential-event-v1.json +81 -0
- package/schemas/credential-v1.json +134 -0
- package/schemas/decision-event-v1.json +288 -0
- package/schemas/delivery-event-v1.json +117 -0
- package/schemas/directory-event-v1.json +85 -0
- package/schemas/evidence-export-v1.json +54 -0
- package/schemas/membership-event-v1.json +93 -0
- package/schemas/policy-v1.json +68 -0
- package/schemas/pushed-policy-v1.json +236 -0
- package/schemas/run-v1.json +162 -0
- package/schemas/snapshot-v1.json +138 -0
- package/schemas/supabase-claims-v1.json +4 -4
- package/schemas/supabase-manifest-v1.json +5 -1
- package/schemas/support-session-v1.json +111 -0
- package/skills/permdock/SKILL.md +16 -12
- package/skills/permdock-agents/SKILL.md +40 -23
- package/skills/permdock-agents/references/operations-automations-chat.md +221 -0
- package/skills/permdock-agents/references/runtimes.md +22 -18
- package/skills/permdock-approvals/SKILL.md +29 -13
- package/skills/permdock-approvals/references/delivery-and-waiters.md +172 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +21 -7
- package/skills/permdock-audit/SKILL.md +3 -3
- package/skills/permdock-credentials/SKILL.md +5 -5
- package/skills/permdock-credentials/references/tokens-keys-links.md +19 -10
- package/skills/permdock-data/SKILL.md +6 -6
- package/skills/permdock-data/references/queries-and-rls.md +13 -8
- package/skills/permdock-data/references/relationships.md +3 -3
- package/skills/permdock-tenancy/SKILL.md +20 -7
- package/skills/permdock-tenancy/references/contacts-and-support-sessions.md +122 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +6 -4
- package/skills/permdock-wire/SKILL.md +18 -12
- package/skills/permdock-wire/references/adapters.md +146 -50
- package/skills/permdock-wire/references/policy-options.md +15 -6
- package/skills/permdock-wire/references/presets-and-recipes.md +58 -0
- package/dist/approvals-DbYAuNkG.js +0 -224
- package/dist/arazzo-C9chp3ST.js +0 -54
- package/dist/bind-C_ob3LKa.d.ts +0 -25
- package/dist/catalog-CRW5Mx_B.js +0 -2
- package/dist/catalog-CYj-mX2O.js +0 -48
- package/dist/catalog-DWF5cYqB.js +0 -55
- package/dist/cloud-CfwZ39Rl.js +0 -50
- package/dist/cloud-DWLXO2af.js +0 -118
- package/dist/collect-CHB22Sx4.js +0 -83
- package/dist/collect-DSWOk19R.js +0 -2
- package/dist/commands-BeaGNj_o.js +0 -97
- package/dist/config-ir40y8m0.js +0 -36
- package/dist/create-CMwIl-w2.js +0 -253
- package/dist/delegation-D8pUEuce.js +0 -103
- package/dist/diff-C9RDjjhs.js +0 -48
- package/dist/doctor-Djh6JDEk.js +0 -53
- package/dist/doctor-DvH0IQff.js +0 -1194
- package/dist/doctor-collect-CjdO0wQX.js +0 -665
- package/dist/duration-xK2jGFVc.js +0 -25
- package/dist/errors-CWfoNg9N.js +0 -47
- package/dist/errors-DRnGZHzF.js +0 -30
- package/dist/evaluation-items-CfCCejQd.js +0 -40
- package/dist/expiry-BoBJ8Tvc.js +0 -7
- package/dist/fields-BMl1RxoX.js +0 -26
- package/dist/grantee-Cv5Sogfv.js +0 -602
- package/dist/headers-BZSDieNT.js +0 -6
- package/dist/headers-Cf-zWvsO.d.ts +0 -6
- package/dist/ids-DC4V4CFu.js +0 -18
- package/dist/index-0nNqHspG.d.ts +0 -6
- package/dist/index-BNc7Wer_.d.ts +0 -483
- package/dist/index-C7Tw7MaW.d.ts +0 -201
- package/dist/instance-options-Dhhcnm3y.js +0 -22
- package/dist/load-DwJUafYN.js +0 -2
- package/dist/manifest-iaoBXHKc.js +0 -783
- package/dist/map-AcxK9o_D.js +0 -147
- package/dist/may-use-DndQ5tQ-.js +0 -77
- package/dist/openapi-CQTsgKoB.js +0 -164
- package/dist/permdock-CbgvLnuo.js +0 -3479
- package/dist/permissions-DVoF6dMt.js +0 -662
- package/dist/policy-xyWg7QdR.js +0 -1122
- package/dist/powersync-CrBX8hY6.js +0 -2
- package/dist/powersync-DE19b9dT.js +0 -62
- package/dist/protected-BdnIEFkY.d.ts +0 -27
- package/dist/protected-xAr24FEC.d.ts +0 -40
- package/dist/relations-cjOL01hZ.js +0 -505
- package/dist/rls-P-BeBx0n.js +0 -238
- package/dist/rls-graph-CHwx0V8q.js +0 -435
- package/dist/rls-ownership-DcYlZ09B.js +0 -843
- package/dist/rls-shared-Cewd_-zI.js +0 -495
- package/dist/rls-verify-CMv9H3wV.js +0 -746
- package/dist/run-BWc9qqvE.js +0 -174
- package/dist/server-DlZ28Oz5.js +0 -268
- package/dist/sink-B1fZzIMf.d.ts +0 -104
- package/dist/sink-Bd9PSyfq.js +0 -141
- package/dist/skills-C5CbhhpG.js +0 -56
- package/dist/snapshot-Enxd0n-s.js +0 -975
- package/dist/sql-xdg5f4Fi.js +0 -27
- package/dist/src-BDwEZWrZ.js +0 -568
- package/dist/store-jOBYpiXC.d.ts +0 -36
- package/dist/stores-C0IMQrGI.d.ts +0 -52
- package/dist/subject-C6dLxqHU.js +0 -24
- package/dist/supabase-config-Bj3iDH2I.js +0 -472
- package/dist/supabase-hook-gd3s8bxB.js +0 -2
- package/dist/supabase-s4o9s1O1.js +0 -83
- package/dist/thenable-okc2xDsj.js +0 -10
- package/dist/types-BnIEz1sU.d.ts +0 -48
- package/dist/types-Bvc4oWT6.d.ts +0 -9
- package/dist/types-CKNSyIf_.d.ts +0 -52
- package/dist/types-Cq_H8N_X.d.ts +0 -197
- package/dist/usage-B0YuTQRO.js +0 -42
- package/dist/usage-DorAJiU_.js +0 -2
- package/dist/vocabulary-DA8a8zif.d.ts +0 -56
- package/dist/watch-BwxLTYMZ.js +0 -2
|
@@ -1,665 +0,0 @@
|
|
|
1
|
-
import { a as hasConditionOp } from "./refs-KYb4ntaz.js";
|
|
2
|
-
import { h as separationConflicts } from "./policy-xyWg7QdR.js";
|
|
3
|
-
import { a as normalizeMemberships, d as scopeList, o as resolveScope } from "./scopes-CVdPrWN-.js";
|
|
4
|
-
import { b as validateCustomRole } from "./permdock-CbgvLnuo.js";
|
|
5
|
-
import { o as parseCredential } from "./credential-8P81ff4u.js";
|
|
6
|
-
import { t as policyRowConditionKeys } from "./row-conditions-h2HythXQ.js";
|
|
7
|
-
import { o as jsonSchemaOf } from "./catalog-doc-DdGm82XT.js";
|
|
8
|
-
import { a as sqlFiles, n as doctorSrcPath } from "./files-DWUN9PzI.js";
|
|
9
|
-
import { a as loadModule, n as asPolicy, o as pickNamed } from "./load-DhWEB9P1.js";
|
|
10
|
-
import { r as runCollect } from "./collect-DSTE3ml9.js";
|
|
11
|
-
import { i as quoteSqlLiteral } from "./sql-xdg5f4Fi.js";
|
|
12
|
-
import "./sources-4p0-4xQm.js";
|
|
13
|
-
import { n as supabaseConfig, r as MIGRATION_DIRS } from "./supabase-config-Bj3iDH2I.js";
|
|
14
|
-
import { T as graphSqlName } from "./rls-shared-Cewd_-zI.js";
|
|
15
|
-
import { W as contextRefs, h as tableFor, p as commandFor } from "./rls-fields-CZOMlwHl.js";
|
|
16
|
-
import { d as rowConditionMessage, l as helperTablePolicies, n as graphPlan, o as ROW_CONDITION_FIX } from "./rls-graph-CHwx0V8q.js";
|
|
17
|
-
import { t as runUsage } from "./usage-ItS7nLcl.js";
|
|
18
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
19
|
-
import { resolve } from "node:path";
|
|
20
|
-
//#region src/cli/doctor-collect.ts
|
|
21
|
-
async function pd002(input) {
|
|
22
|
-
const collected = await collectedOf(input);
|
|
23
|
-
if (collected.scan === void 0) return [];
|
|
24
|
-
return collected.scan.unknown.map((usage) => ({
|
|
25
|
-
code: "PD002",
|
|
26
|
-
severity: "error",
|
|
27
|
-
message: `unknown permission ${usage.call} at ${usage.file}:${String(usage.line)}`,
|
|
28
|
-
fix: "use a defined permission reference"
|
|
29
|
-
}));
|
|
30
|
-
}
|
|
31
|
-
async function pd003(input) {
|
|
32
|
-
if (input.config.policy === void 0) return [];
|
|
33
|
-
const usage = await runUsage({
|
|
34
|
-
cwd: input.cwd,
|
|
35
|
-
config: input.config,
|
|
36
|
-
ignore: [],
|
|
37
|
-
strict: false,
|
|
38
|
-
json: true,
|
|
39
|
-
dynamicAsUsed: false,
|
|
40
|
-
now: input.now,
|
|
41
|
-
io: input.io,
|
|
42
|
-
collected: () => collectedOf(input),
|
|
43
|
-
policy: () => policyOf(input)
|
|
44
|
-
});
|
|
45
|
-
if (usage.code === 2) return [];
|
|
46
|
-
return JSON.parse(usage.output).ungranted.map((item) => ({
|
|
47
|
-
code: "PD003",
|
|
48
|
-
severity: "warning",
|
|
49
|
-
message: `${item.key} is used but never granted (${item.detail})`,
|
|
50
|
-
fix: "add an allow() with a to: selector, or a role() binding, in definePolicy"
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
async function pd004(input) {
|
|
54
|
-
const collected = await collectedOf(input);
|
|
55
|
-
if (collected.code === 0) return [];
|
|
56
|
-
if (collected.code === 2) return [];
|
|
57
|
-
return [{
|
|
58
|
-
code: "PD004",
|
|
59
|
-
severity: "error",
|
|
60
|
-
message: collected.message,
|
|
61
|
-
fix: "pnpm exec permdock collect"
|
|
62
|
-
}];
|
|
63
|
-
}
|
|
64
|
-
async function pd027(input) {
|
|
65
|
-
if (input.config.rls === void 0 || input.config.policy === void 0) return [];
|
|
66
|
-
const policy = await policyOf(input);
|
|
67
|
-
if (policy === void 0) return [];
|
|
68
|
-
const findings = [];
|
|
69
|
-
for (const grant of policy.grants) {
|
|
70
|
-
const refs = [.../* @__PURE__ */ new Set([...contextRefs(grant.where), ...contextRefs(grant.check)])];
|
|
71
|
-
if (refs.length === 0) continue;
|
|
72
|
-
findings.push({
|
|
73
|
-
code: "PD027",
|
|
74
|
-
severity: "warning",
|
|
75
|
-
message: `${grant.permission.key}${grant.role === null ? "" : ` (role ${grant.role})`} reads ${refs.join(", ")}: request context is not in the token, so permdock rls generate cannot compile it and the database cannot enforce it`,
|
|
76
|
-
fix: "move the value to a server-set claim and compare with principal.claims.<name>, or keep the check API-side and pass --skip-closures to rls generate"
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
return findings;
|
|
80
|
-
}
|
|
81
|
-
async function pd016(input) {
|
|
82
|
-
if (input.config.rls === void 0 || input.config.policy === void 0) return [];
|
|
83
|
-
const policy = await policyOf(input);
|
|
84
|
-
if (policy === void 0) return [];
|
|
85
|
-
const findings = [];
|
|
86
|
-
let opaque = false;
|
|
87
|
-
let sqlFunction = false;
|
|
88
|
-
for (const grant of policy.grants) {
|
|
89
|
-
if (hasConditionOp(grant.where, "opaque") || hasConditionOp(grant.check, "opaque")) opaque = true;
|
|
90
|
-
if (hasConditionOp(grant.where, "sqlFunction") || hasConditionOp(grant.check, "sqlFunction")) sqlFunction = true;
|
|
91
|
-
}
|
|
92
|
-
if (opaque) findings.push({
|
|
93
|
-
code: "PD016",
|
|
94
|
-
severity: "warning",
|
|
95
|
-
message: "policy has opaque RLS conditions that deny in memory",
|
|
96
|
-
fix: "add rls.functions.<name> with a portable twin, or rewrite as sqlFunction()"
|
|
97
|
-
});
|
|
98
|
-
if (sqlFunction) {
|
|
99
|
-
const fixtures = input.config.rls.fixtures ?? "rls.fixtures.json";
|
|
100
|
-
if (!existsSync(resolve(input.cwd, fixtures)) && !existsSync(resolve(input.cwd, "rls.fixtures.ts"))) findings.push({
|
|
101
|
-
code: "PD016",
|
|
102
|
-
severity: "warning",
|
|
103
|
-
message: "sqlFunction grants have no rls fixtures for verify --db",
|
|
104
|
-
fix: "add rls.fixtures.json and run permdock rls verify --db"
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
return findings;
|
|
108
|
-
}
|
|
109
|
-
const DEFAULT_SENSITIVE_ACTIONS = [
|
|
110
|
-
"approve",
|
|
111
|
-
"pay",
|
|
112
|
-
"settle",
|
|
113
|
-
"submit",
|
|
114
|
-
"transfer",
|
|
115
|
-
"refund",
|
|
116
|
-
"disburse"
|
|
117
|
-
];
|
|
118
|
-
async function loadPolicy(cwd, path) {
|
|
119
|
-
try {
|
|
120
|
-
return asPolicy(pickNamed(await loadModule(resolve(cwd, path)), ["policy"]));
|
|
121
|
-
} catch {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/** The configured policy, through the project's memoised load when there is one. */
|
|
126
|
-
function policyOf(input) {
|
|
127
|
-
const path = input.config.policy;
|
|
128
|
-
if (path === void 0) return Promise.resolve(void 0);
|
|
129
|
-
return input.policy === void 0 ? loadPolicy(input.cwd, path) : input.policy();
|
|
130
|
-
}
|
|
131
|
-
/** `collect --check`, through the project's memoised run when there is one. */
|
|
132
|
-
function collectedOf(input) {
|
|
133
|
-
return input.collected === void 0 ? runCollect({
|
|
134
|
-
cwd: input.cwd,
|
|
135
|
-
config: input.config,
|
|
136
|
-
collect: input.config.collect ?? {},
|
|
137
|
-
scanPath: doctorSrcPath(input.config),
|
|
138
|
-
check: true,
|
|
139
|
-
now: input.now,
|
|
140
|
-
io: input.io
|
|
141
|
-
}) : input.collected();
|
|
142
|
-
}
|
|
143
|
-
async function pd017(input) {
|
|
144
|
-
if (input.config.policy === void 0) return [];
|
|
145
|
-
const policy = await policyOf(input);
|
|
146
|
-
if (policy === void 0) return [];
|
|
147
|
-
const sensitive = new Set(input.config.doctor?.sensitiveActions ?? DEFAULT_SENSITIVE_ACTIONS);
|
|
148
|
-
const denied = new Set(policy.grants.filter((grant) => grant.effect === "deny").map((grant) => grant.permission.key));
|
|
149
|
-
const findings = [];
|
|
150
|
-
const seen = /* @__PURE__ */ new Set();
|
|
151
|
-
for (const grant of policy.grants) {
|
|
152
|
-
if (grant.effect !== "allow") continue;
|
|
153
|
-
if (!sensitive.has(grant.permission.action)) continue;
|
|
154
|
-
if (grant.approval !== void 0) continue;
|
|
155
|
-
if (denied.has(grant.permission.key)) continue;
|
|
156
|
-
if (seen.has(grant.permission.key)) continue;
|
|
157
|
-
seen.add(grant.permission.key);
|
|
158
|
-
findings.push({
|
|
159
|
-
code: "PD017",
|
|
160
|
-
severity: "warning",
|
|
161
|
-
message: `${grant.permission.key} is a sensitive verb without approval`,
|
|
162
|
-
fix: "add approval: { by } on the allow, or a deny on the same leaf"
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
return findings;
|
|
166
|
-
}
|
|
167
|
-
async function pd024(input) {
|
|
168
|
-
if (input.config.policy === void 0) return [];
|
|
169
|
-
const policy = await policyOf(input);
|
|
170
|
-
if (policy === void 0) return [];
|
|
171
|
-
const findings = [];
|
|
172
|
-
for (const grant of policy.grants) {
|
|
173
|
-
const approval = grant.approval;
|
|
174
|
-
if (grant.effect !== "allow" || approval === void 0 || approval === "human" || approval.distinct !== false) continue;
|
|
175
|
-
findings.push({
|
|
176
|
-
code: "PD024",
|
|
177
|
-
severity: "warning",
|
|
178
|
-
message: `${grant.permission.key}${grant.role === null ? "" : ` (role ${grant.role})`} sets approval.distinct: false, so the requester can approve their own request`,
|
|
179
|
-
fix: "remove distinct: false unless the requester confirming their own call (an agent asking its user) is the intent"
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return findings;
|
|
183
|
-
}
|
|
184
|
-
function asMembershipsFixture(parsed) {
|
|
185
|
-
return parsed !== null && typeof parsed === "object" ? parsed : {};
|
|
186
|
-
}
|
|
187
|
-
async function pd018(input) {
|
|
188
|
-
if (input.config.policy === void 0) return [];
|
|
189
|
-
const policy = await policyOf(input);
|
|
190
|
-
if (policy === void 0) return [];
|
|
191
|
-
const findings = [];
|
|
192
|
-
const declared = new Set(policy.roles.map((item) => item.name));
|
|
193
|
-
for (const binding of policy.roles) for (const name of binding.exclusiveWith ?? []) if (!declared.has(name)) findings.push({
|
|
194
|
-
code: "PD018",
|
|
195
|
-
severity: "error",
|
|
196
|
-
message: `exclusiveWith names undeclared role ${name} on ${binding.name}`,
|
|
197
|
-
fix: "declare the exclusive role with role() or remove it from exclusiveWith"
|
|
198
|
-
});
|
|
199
|
-
const fixturePath = input.config.doctor?.memberships;
|
|
200
|
-
if (fixturePath === void 0) return findings;
|
|
201
|
-
const absolute = resolve(input.cwd, fixturePath);
|
|
202
|
-
if (!existsSync(absolute)) {
|
|
203
|
-
findings.push({
|
|
204
|
-
code: "PD018",
|
|
205
|
-
severity: "warning",
|
|
206
|
-
message: `doctor.memberships fixture ${fixturePath} is missing`,
|
|
207
|
-
fix: "add the JSON fixture or remove doctor.memberships"
|
|
208
|
-
});
|
|
209
|
-
return findings;
|
|
210
|
-
}
|
|
211
|
-
let parsed;
|
|
212
|
-
try {
|
|
213
|
-
parsed = JSON.parse(readFileSync(absolute, "utf8"));
|
|
214
|
-
} catch {
|
|
215
|
-
findings.push({
|
|
216
|
-
code: "PD018",
|
|
217
|
-
severity: "warning",
|
|
218
|
-
message: `doctor.memberships fixture ${fixturePath} is not valid JSON`,
|
|
219
|
-
fix: "fix the JSON fixture"
|
|
220
|
-
});
|
|
221
|
-
return findings;
|
|
222
|
-
}
|
|
223
|
-
const record = asMembershipsFixture(parsed);
|
|
224
|
-
for (const custom of record.customRoles ?? []) {
|
|
225
|
-
const conflicts = separationConflicts(policy, [{
|
|
226
|
-
principal: custom.name,
|
|
227
|
-
...custom.tenant === void 0 ? {} : { tenant: custom.tenant },
|
|
228
|
-
roles: custom.includes ?? []
|
|
229
|
-
}]);
|
|
230
|
-
for (const conflict of conflicts) findings.push({
|
|
231
|
-
code: "PD018",
|
|
232
|
-
severity: "warning",
|
|
233
|
-
message: `custom role ${custom.name} includes exclusive roles ${conflict.roles.join(" and ")}`,
|
|
234
|
-
fix: "split the custom role so it does not include exclusiveWith pairs"
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
for (const conflict of separationConflicts(policy, record.memberships ?? [])) findings.push({
|
|
238
|
-
code: "PD018",
|
|
239
|
-
severity: "warning",
|
|
240
|
-
message: `membership ${conflict.principal || "unknown"} holds exclusive roles ${conflict.roles.join(" and ")}`,
|
|
241
|
-
fix: "remove one of the exclusive roles from the membership fixture"
|
|
242
|
-
});
|
|
243
|
-
return findings;
|
|
244
|
-
}
|
|
245
|
-
async function pd020(input) {
|
|
246
|
-
if (input.config.rls === void 0 || input.config.policy === void 0) return [];
|
|
247
|
-
const policy = await policyOf(input);
|
|
248
|
-
if (policy === void 0) return [];
|
|
249
|
-
const tables = input.config.rls.tables;
|
|
250
|
-
const compiled = (policy.hostable ?? []).filter((key) => {
|
|
251
|
-
const resource = key.slice(0, key.lastIndexOf("."));
|
|
252
|
-
return tables === void 0 || tables[resource] !== void 0;
|
|
253
|
-
});
|
|
254
|
-
if (compiled.length === 0) return [];
|
|
255
|
-
return [{
|
|
256
|
-
code: "PD020",
|
|
257
|
-
severity: "warning",
|
|
258
|
-
message: `hostable permissions are also compiled into RLS, which never sees hosted grants: ${compiled.join(", ")}`,
|
|
259
|
-
fix: "remove them from hostable, or drop their tables from rls.tables and enforce them in the application"
|
|
260
|
-
}];
|
|
261
|
-
}
|
|
262
|
-
async function pd021(input) {
|
|
263
|
-
if (input.config.policy === void 0) return [];
|
|
264
|
-
const policy = await policyOf(input);
|
|
265
|
-
if (policy === void 0 || (policy.hostable ?? []).length === 0) return [];
|
|
266
|
-
const missing = ["PERMDOCK_CLOUD_URL", "PERMDOCK_CLOUD_KEY"].filter((name) => (input.env[name] ?? "") === "");
|
|
267
|
-
if (missing.length === 0) return [];
|
|
268
|
-
return [{
|
|
269
|
-
code: "PD021",
|
|
270
|
-
severity: "warning",
|
|
271
|
-
message: `the policy lists hostable permissions but ${missing.join(" and ")} is not set, so no hosted grant can be published or fetched`,
|
|
272
|
-
fix: "set the variables from the PermDock Cloud dashboard, or remove hostable"
|
|
273
|
-
}];
|
|
274
|
-
}
|
|
275
|
-
async function pd019(input) {
|
|
276
|
-
const rls = input.config.rls;
|
|
277
|
-
if ((rls?.authorize ?? rls?.rbac?.authorize) !== "jwt") return [];
|
|
278
|
-
const expiry = supabaseConfig(input.cwd).jwtExpiry ?? 3600;
|
|
279
|
-
if (expiry <= 3600 || input.config.policy === void 0) return [];
|
|
280
|
-
const policy = await policyOf(input);
|
|
281
|
-
if (policy === void 0) return [];
|
|
282
|
-
const sensitive = new Set(input.config.doctor?.sensitiveActions ?? DEFAULT_SENSITIVE_ACTIONS);
|
|
283
|
-
const keys = [...new Set(policy.grants.filter((grant) => grant.effect === "allow" && sensitive.has(grant.permission.action)).map((grant) => grant.permission.key))];
|
|
284
|
-
if (keys.length === 0) return [];
|
|
285
|
-
return [{
|
|
286
|
-
code: "PD019",
|
|
287
|
-
severity: "warning",
|
|
288
|
-
message: `the RLS helpers and authorize() read roles from the JWT and jwt_expiry is ${String(expiry)}s: a revoked role keeps ${keys.join(", ")} until the token expires`,
|
|
289
|
-
fix: "set rls.authorize: 'database', or lower [auth] jwt_expiry in supabase/config.toml to 3600 or less"
|
|
290
|
-
}];
|
|
291
|
-
}
|
|
292
|
-
function customRoleLabel(role) {
|
|
293
|
-
return role.tenant === void 0 ? `global custom role ${role.name}` : `custom role ${role.name} in ${role.tenant}`;
|
|
294
|
-
}
|
|
295
|
-
async function pd023(input) {
|
|
296
|
-
const fixturePath = input.config.doctor?.memberships;
|
|
297
|
-
if (input.config.policy === void 0 || fixturePath === void 0) return [];
|
|
298
|
-
const absolute = resolve(input.cwd, fixturePath);
|
|
299
|
-
if (!existsSync(absolute)) return [];
|
|
300
|
-
let parsed;
|
|
301
|
-
try {
|
|
302
|
-
parsed = JSON.parse(readFileSync(absolute, "utf8"));
|
|
303
|
-
} catch {
|
|
304
|
-
return [];
|
|
305
|
-
}
|
|
306
|
-
const policy = await policyOf(input);
|
|
307
|
-
if (policy === void 0) return [];
|
|
308
|
-
const findings = [];
|
|
309
|
-
for (const custom of asMembershipsFixture(parsed).customRoles ?? []) for (const entry of validateCustomRole(policy, custom).dropped) {
|
|
310
|
-
const what = "role" in entry ? `include ${entry.role}` : `permission ${entry.permission}`;
|
|
311
|
-
findings.push({
|
|
312
|
-
code: "PD023",
|
|
313
|
-
severity: "warning",
|
|
314
|
-
message: `${customRoleLabel(custom)} drops ${what} (${entry.reason})`,
|
|
315
|
-
fix: entry.reason === "outside-ceiling" ? "grant it to a declared assignable role, or remove it from the custom role" : entry.reason === "condition-not-allowed" ? "remove the condition; custom-role grants inherit the declared grant condition" : "use a declared permission key or assignable role name"
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
return findings;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* PD055: a stored custom role names a permission by a key it was renamed
|
|
322
|
-
* from. It still resolves; the alias can only be dropped once storage holds
|
|
323
|
-
* the current key.
|
|
324
|
-
*/
|
|
325
|
-
async function pd055(input) {
|
|
326
|
-
const fixturePath = input.config.doctor?.memberships;
|
|
327
|
-
if (input.config.policy === void 0 || fixturePath === void 0) return [];
|
|
328
|
-
const absolute = resolve(input.cwd, fixturePath);
|
|
329
|
-
if (!existsSync(absolute)) return [];
|
|
330
|
-
let parsed;
|
|
331
|
-
try {
|
|
332
|
-
parsed = JSON.parse(readFileSync(absolute, "utf8"));
|
|
333
|
-
} catch {
|
|
334
|
-
return [];
|
|
335
|
-
}
|
|
336
|
-
const policy = await policyOf(input);
|
|
337
|
-
if (policy === void 0) return [];
|
|
338
|
-
const table = `${input.config.rls?.schema ?? "permdock"}.custom_role_permissions`;
|
|
339
|
-
const findings = [];
|
|
340
|
-
for (const custom of asMembershipsFixture(parsed).customRoles ?? []) for (const { from, to } of validateCustomRole(policy, custom).renamed) findings.push({
|
|
341
|
-
code: "PD055",
|
|
342
|
-
severity: "warning",
|
|
343
|
-
message: `${customRoleLabel(custom)} stores ${from}, which was renamed to ${to}`,
|
|
344
|
-
fix: `rewrite the stored key before removing the alias: update ${table} set permission = ${quoteSqlLiteral(to)} where permission = ${quoteSqlLiteral(from)};`
|
|
345
|
-
});
|
|
346
|
-
return findings;
|
|
347
|
-
}
|
|
348
|
-
function readJson(cwd, path) {
|
|
349
|
-
if (path === void 0) return;
|
|
350
|
-
const absolute = resolve(cwd, path);
|
|
351
|
-
if (!existsSync(absolute)) return;
|
|
352
|
-
try {
|
|
353
|
-
return JSON.parse(readFileSync(absolute, "utf8"));
|
|
354
|
-
} catch {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
function listField(value, field) {
|
|
359
|
-
if (value === null || typeof value !== "object") return [];
|
|
360
|
-
const list = value[field];
|
|
361
|
-
return Array.isArray(list) ? list : [];
|
|
362
|
-
}
|
|
363
|
-
/** Fixture API keys that never expire, credential policies that allow it, and records that are not v1 credentials. */
|
|
364
|
-
function pd029(input) {
|
|
365
|
-
const parsed = readJson(input.cwd, input.config.doctor?.credentials);
|
|
366
|
-
const findings = [];
|
|
367
|
-
for (const [index, record] of listField(parsed, "credentials").entries()) {
|
|
368
|
-
const credential = parseCredential(record);
|
|
369
|
-
if (credential === void 0) {
|
|
370
|
-
findings.push({
|
|
371
|
-
code: "PD029",
|
|
372
|
-
severity: "warning",
|
|
373
|
-
message: `credentials[${String(index)}] is not a valid v1 credential, so it verifies to no subject`,
|
|
374
|
-
fix: "give it v: 1, id, kind, principal, permissions, createdBy and createdAt; a service key also needs tenant and roles"
|
|
375
|
-
});
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
if (credential.expiresAt === void 0) findings.push({
|
|
379
|
-
code: "PD029",
|
|
380
|
-
severity: "warning",
|
|
381
|
-
message: `API key ${credential.id} never expires`,
|
|
382
|
-
fix: "set expiresAt and rotate the key before it; a leaked key without expiry stays live until someone revokes it"
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
const settings = parsed !== null && typeof parsed === "object" ? parsed.settings : void 0;
|
|
386
|
-
const tenants = settings !== null && typeof settings === "object" ? Object.entries(settings) : [];
|
|
387
|
-
for (const [tenant, value] of tenants) if ((value !== null && typeof value === "object" ? value.credentials : void 0)?.allowNoExpiry === true) findings.push({
|
|
388
|
-
code: "PD029",
|
|
389
|
-
severity: "warning",
|
|
390
|
-
message: `tenant ${tenant} allows API keys that never expire`,
|
|
391
|
-
fix: "drop allowNoExpiry and set maxTtl, or keep it only for a tenant that rotates keys on its own schedule"
|
|
392
|
-
});
|
|
393
|
-
return findings;
|
|
394
|
-
}
|
|
395
|
-
/** Fixture memberships the policy's scopes would drop: an undeclared scope, a missing parent id, mixed shapes. */
|
|
396
|
-
/**
|
|
397
|
-
* A scope whose roles can all be removed can end up with nobody able to
|
|
398
|
-
* manage it. Setting `min` on any of its roles (even `min: 0`) records the
|
|
399
|
-
* decision and silences the warning.
|
|
400
|
-
*/
|
|
401
|
-
async function pd026(input) {
|
|
402
|
-
if (input.config.policy === void 0) return [];
|
|
403
|
-
const policy = await policyOf(input);
|
|
404
|
-
if (policy === void 0) return [];
|
|
405
|
-
const scopes = scopeList(policy.scopes);
|
|
406
|
-
const findings = [];
|
|
407
|
-
for (const { name } of scopes) {
|
|
408
|
-
const held = policy.roles.filter((binding) => typeof binding.on === "string" && resolveScope(scopes, binding.on) === name);
|
|
409
|
-
if (held.length === 0 || held.some((binding) => binding.min !== void 0)) continue;
|
|
410
|
-
findings.push({
|
|
411
|
-
code: "PD026",
|
|
412
|
-
severity: "warning",
|
|
413
|
-
message: `no role on scope '${name}' keeps a holder: every ${name} can lose its last ${held.map((binding) => binding.name).join(" / ")}`,
|
|
414
|
-
fix: `set min: 1 on the role that manages a ${name} (role(..., { on: '${name}', min: 1 })), or min: 0 to record that none must stay`
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
return findings;
|
|
418
|
-
}
|
|
419
|
-
async function pd025(input) {
|
|
420
|
-
const fixturePath = input.config.doctor?.memberships;
|
|
421
|
-
if (input.config.policy === void 0 || fixturePath === void 0) return [];
|
|
422
|
-
const absolute = resolve(input.cwd, fixturePath);
|
|
423
|
-
if (!existsSync(absolute)) return [];
|
|
424
|
-
let parsed;
|
|
425
|
-
try {
|
|
426
|
-
parsed = JSON.parse(readFileSync(absolute, "utf8"));
|
|
427
|
-
} catch {
|
|
428
|
-
return [];
|
|
429
|
-
}
|
|
430
|
-
const policy = await policyOf(input);
|
|
431
|
-
if (policy === void 0) return [];
|
|
432
|
-
const scopes = scopeList(policy.scopes);
|
|
433
|
-
const names = scopes.map((scope) => scope.name).join(", ");
|
|
434
|
-
const findings = [];
|
|
435
|
-
for (const [index, membership] of (asMembershipsFixture(parsed).memberships ?? []).entries()) {
|
|
436
|
-
if (normalizeMemberships([membership], scopes).length > 0) continue;
|
|
437
|
-
findings.push({
|
|
438
|
-
code: "PD025",
|
|
439
|
-
severity: "warning",
|
|
440
|
-
message: `membership ${membership.principal ?? String(index)} grants nothing: its scope is not one of ${names}, a parent id is missing from within, or it mixes shapes`,
|
|
441
|
-
fix: "use { scope, id, within: { <parent>: id }, roles } with a declared scope, or { on: { resource, id }, roles }"
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
return findings;
|
|
445
|
-
}
|
|
446
|
-
/** Columns of `resource` a field-limited read grant can hide: missing from an allow's list, or on a deny's. */
|
|
447
|
-
function limitedColumns(policy, resource, actions) {
|
|
448
|
-
const reads = policy.grants.filter((grant) => grant.permission.resource === resource && grant.fields !== void 0 && commandFor(grant.permission.action, actions) === "select");
|
|
449
|
-
const node = policy.resources.get(resource);
|
|
450
|
-
const schema = node === void 0 ? null : jsonSchemaOf(node);
|
|
451
|
-
const properties = schema !== null && typeof schema === "object" ? schema.properties : void 0;
|
|
452
|
-
const columns = properties !== null && typeof properties === "object" ? Object.keys(properties) : [...new Set(reads.flatMap((grant) => grant.fields ?? []))];
|
|
453
|
-
const key = node?.id ?? "id";
|
|
454
|
-
return columns.filter((column) => column !== key && reads.some((grant) => grant.effect === "deny" ? (grant.fields ?? []).includes(column) : !(grant.fields ?? []).includes(column)));
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* `fields` redact in the application; RLS is row-level unless field views
|
|
458
|
-
* compile, and a field view protects nothing while the base table still
|
|
459
|
-
* returns the columns to a direct read.
|
|
460
|
-
*/
|
|
461
|
-
async function pd030(input) {
|
|
462
|
-
const rls = input.config.rls;
|
|
463
|
-
if (rls === void 0 || input.config.policy === void 0) return [];
|
|
464
|
-
const policy = await policyOf(input);
|
|
465
|
-
if (policy === void 0) return [];
|
|
466
|
-
const resources = [...new Set(policy.grants.filter((grant) => grant.fields !== void 0 && commandFor(grant.permission.action, rls.actions) === "select").map((grant) => grant.permission.resource))].toSorted();
|
|
467
|
-
const findings = [];
|
|
468
|
-
for (const resource of resources) {
|
|
469
|
-
const columns = limitedColumns(policy, resource, rls.actions);
|
|
470
|
-
if (columns.length === 0) continue;
|
|
471
|
-
const table = tableFor(resource, rls.tables);
|
|
472
|
-
if (rls.fields !== "views") {
|
|
473
|
-
findings.push({
|
|
474
|
-
code: "PD030",
|
|
475
|
-
severity: "warning",
|
|
476
|
-
message: `read grants on ${resource} limit ${columns.join(", ")}, but RLS on ${table} is row-level: any client that reads ${table} directly gets those columns`,
|
|
477
|
-
fix: `set rls.fields: 'views' and rls.revokeColumns: true (permdock rls generate --fields views --revoke-columns), or keep direct reads server-side and redact with pick`
|
|
478
|
-
});
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
if (rls.revokeColumns !== true) findings.push({
|
|
482
|
-
code: "PD030",
|
|
483
|
-
severity: "warning",
|
|
484
|
-
message: `${table}_visible masks ${columns.join(", ")}, but ${table} still returns them to a direct read`,
|
|
485
|
-
fix: `set rls.revokeColumns: true (--revoke-columns) so clients read ${columns.join(", ")} only through ${table}_visible`
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
return findings;
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* A self-parented resource no `through` grant walks, or a `restricted`
|
|
492
|
-
* column no graph grant reaches: the declaration has no effect on any
|
|
493
|
-
* decision, and `rls generate` keeps no closure for it.
|
|
494
|
-
*/
|
|
495
|
-
async function pd031(input) {
|
|
496
|
-
if (input.config.policy === void 0) return [];
|
|
497
|
-
const policy = await policyOf(input);
|
|
498
|
-
if (policy === void 0) return [];
|
|
499
|
-
const plan = graphPlan(policy);
|
|
500
|
-
const findings = [];
|
|
501
|
-
for (const node of policy.resources.values()) {
|
|
502
|
-
const walked = plan.get(node.name)?.closure !== void 0;
|
|
503
|
-
if (node.parent?.resource === node.name && !walked) findings.push({
|
|
504
|
-
code: "PD031",
|
|
505
|
-
severity: "warning",
|
|
506
|
-
message: `${node.name} parents itself through ${node.parent.field}, but no grant walks it with relation(..., { through: 'parent' }): its ancestors grant nothing and rls generate keeps no closure for it`,
|
|
507
|
-
fix: `grant through the chain (relation(permissions.${node.name}, '<relation>', { through: 'parent', depth: 16 })) or drop the self-parent`
|
|
508
|
-
});
|
|
509
|
-
const reached = [...plan.values()].some((entry) => entry.node.name === node.name || node.parent?.resource === entry.node.name && entry.node.name !== node.name);
|
|
510
|
-
if (node.restricted !== void 0 && !reached) findings.push({
|
|
511
|
-
code: "PD031",
|
|
512
|
-
severity: "warning",
|
|
513
|
-
message: `${node.name} declares restricted: '${node.restricted}', but no graph grant reaches ${node.name} rows, so the column keeps nothing out`,
|
|
514
|
-
fix: `add a relation(..., { through: 'parent' }) grant that reaches ${node.name}, or remove restricted`
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
return findings;
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Under an `rls` config, a graph resource `rls generate` cannot name a helper
|
|
521
|
-
* for: one that shares a scope's name (its `permitted_<name>_ids` would
|
|
522
|
-
* replace the scope helper) or is not a lowercase SQL name.
|
|
523
|
-
*/
|
|
524
|
-
async function pd032(input) {
|
|
525
|
-
if (input.config.rls === void 0 || input.config.policy === void 0) return [];
|
|
526
|
-
const policy = await policyOf(input);
|
|
527
|
-
if (policy === void 0) return [];
|
|
528
|
-
const scopes = scopeList(policy.scopes);
|
|
529
|
-
const findings = [];
|
|
530
|
-
const sqlNames = /* @__PURE__ */ new Map();
|
|
531
|
-
for (const name of graphPlan(policy).keys()) {
|
|
532
|
-
const sql = graphSqlName(name);
|
|
533
|
-
if (sql === void 0) {
|
|
534
|
-
findings.push({
|
|
535
|
-
code: "PD032",
|
|
536
|
-
severity: "error",
|
|
537
|
-
message: `graph resource ${name} is not a SQL name, so rls generate cannot name its permitted_<name>_ids helper`,
|
|
538
|
-
fix: "rename the resource to letters, digits and underscores, starting with a letter"
|
|
539
|
-
});
|
|
540
|
-
continue;
|
|
541
|
-
}
|
|
542
|
-
if (scopes.some((scope) => scope.name === sql)) findings.push({
|
|
543
|
-
code: "PD032",
|
|
544
|
-
severity: "error",
|
|
545
|
-
message: `graph resource ${name} shares its SQL name with the ${sql} scope: permitted_${sql}_ids would replace the scope helper, so rls generate refuses it`,
|
|
546
|
-
fix: `rename the resource (for example ${sql}s or ${sql}_node) or the scope`
|
|
547
|
-
});
|
|
548
|
-
const other = sqlNames.get(sql);
|
|
549
|
-
if (other !== void 0) findings.push({
|
|
550
|
-
code: "PD032",
|
|
551
|
-
severity: "error",
|
|
552
|
-
message: `graph resources ${other} and ${name} both become permitted_${sql}_ids in SQL, so rls generate refuses them`,
|
|
553
|
-
fix: "rename one of the resources"
|
|
554
|
-
});
|
|
555
|
-
sqlNames.set(sql, name);
|
|
556
|
-
}
|
|
557
|
-
return findings;
|
|
558
|
-
}
|
|
559
|
-
/** Reads the doctor memberships fixture, if one is configured and parseable. */
|
|
560
|
-
function membershipsFixture(input) {
|
|
561
|
-
const fixturePath = input.config.doctor?.memberships;
|
|
562
|
-
if (fixturePath === void 0) return {};
|
|
563
|
-
const absolute = resolve(input.cwd, fixturePath);
|
|
564
|
-
if (!existsSync(absolute)) return {};
|
|
565
|
-
try {
|
|
566
|
-
return asMembershipsFixture(JSON.parse(readFileSync(absolute, "utf8")));
|
|
567
|
-
} catch {
|
|
568
|
-
return {};
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* PD033: a role activation without a `maxDuration` (an elevation with no
|
|
573
|
-
* ceiling never expires on its own), and an activation role that a fixture
|
|
574
|
-
* membership also holds standing (an eligible-only role must never be held
|
|
575
|
-
* directly).
|
|
576
|
-
*/
|
|
577
|
-
async function pd033(input) {
|
|
578
|
-
if (input.config.policy === void 0) return [];
|
|
579
|
-
const policy = await policyOf(input);
|
|
580
|
-
if (policy === void 0) return [];
|
|
581
|
-
const findings = [];
|
|
582
|
-
const activation = /* @__PURE__ */ new Set();
|
|
583
|
-
for (const binding of policy.roles) {
|
|
584
|
-
if (binding.activation === void 0) continue;
|
|
585
|
-
activation.add(binding.name);
|
|
586
|
-
if (binding.activation.maxDuration === void 0) findings.push({
|
|
587
|
-
code: "PD033",
|
|
588
|
-
severity: "warning",
|
|
589
|
-
message: `role '${binding.name}' has activation without maxDuration: an elevation never expires on its own`,
|
|
590
|
-
fix: `set activation: { maxDuration: '4h', ... } on role '${binding.name}'`
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
const fixture = membershipsFixture(input);
|
|
594
|
-
const standing = /* @__PURE__ */ new Set();
|
|
595
|
-
const eligible = /* @__PURE__ */ new Set();
|
|
596
|
-
for (const membership of fixture.memberships ?? []) {
|
|
597
|
-
for (const name of membership.roles ?? []) standing.add(name);
|
|
598
|
-
for (const name of membership.eligible ?? []) eligible.add(name);
|
|
599
|
-
}
|
|
600
|
-
for (const name of activation) if (standing.has(name)) findings.push({
|
|
601
|
-
code: "PD033",
|
|
602
|
-
severity: "warning",
|
|
603
|
-
message: `activation role '${name}' is held standing by a fixture membership: an eligible-only role must never be held directly`,
|
|
604
|
-
fix: `list '${name}' under eligible, never roles, and activate it with permdock.activate`
|
|
605
|
-
});
|
|
606
|
-
return findings;
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* PD034: a break-glass grant under an `rls` config. RLS never compiles a
|
|
610
|
-
* break-glass override; the server must read through a `security definer`
|
|
611
|
-
* function that checks a signed break-glass session and writes an audit row.
|
|
612
|
-
*/
|
|
613
|
-
async function pd034(input) {
|
|
614
|
-
if (input.config.policy === void 0 || input.config.rls === void 0) return [];
|
|
615
|
-
const policy = await policyOf(input);
|
|
616
|
-
if (policy === void 0) return [];
|
|
617
|
-
const keys = /* @__PURE__ */ new Set();
|
|
618
|
-
for (const grant of policy.grants) if (grant.breakGlass !== void 0) keys.add(grant.permission.key);
|
|
619
|
-
return [...keys].map((key) => ({
|
|
620
|
-
code: "PD034",
|
|
621
|
-
severity: "warning",
|
|
622
|
-
message: `break-glass grant on ${key} cannot be compiled to RLS: it would leak the override into a database policy`,
|
|
623
|
-
fix: "read break-glass rows through a security definer function that checks a signed break-glass session and writes an audit row"
|
|
624
|
-
}));
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* PD035: a `supportAccess` role without `actorRequired`. Support access is
|
|
628
|
-
* impersonation; without an actor the session is unattributed.
|
|
629
|
-
*/
|
|
630
|
-
async function pd035(input) {
|
|
631
|
-
if (input.config.policy === void 0) return [];
|
|
632
|
-
const policy = await policyOf(input);
|
|
633
|
-
if (policy === void 0) return [];
|
|
634
|
-
const findings = [];
|
|
635
|
-
for (const binding of policy.roles) if (binding.support !== void 0 && !binding.support.actorRequired) findings.push({
|
|
636
|
-
code: "PD035",
|
|
637
|
-
severity: "warning",
|
|
638
|
-
message: `support access role '${binding.name}' has actorRequired: false: a support session then runs as the tenant, unattributed`,
|
|
639
|
-
fix: `set actorRequired: true on supportAccess({ role: '${binding.name}', ... })`
|
|
640
|
-
});
|
|
641
|
-
return findings;
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* Storage and Realtime policies written outside PermDock that call the SQL helpers for a permission whose grants
|
|
645
|
-
* carry row conditions: the helpers check only role and scope.
|
|
646
|
-
*/
|
|
647
|
-
async function pd037(input) {
|
|
648
|
-
if (input.config.policy === void 0) return [];
|
|
649
|
-
const policy = await policyOf(input);
|
|
650
|
-
if (policy === void 0) return [];
|
|
651
|
-
const conditioned = policyRowConditionKeys(policy);
|
|
652
|
-
const findings = [];
|
|
653
|
-
for (const file of sqlFiles(input.cwd, input.config.doctor?.migrations ?? MIGRATION_DIRS)) for (const found of helperTablePolicies(readFileSync(file, "utf8"))) {
|
|
654
|
-
const keys = found.keys.filter((key) => conditioned.has(key));
|
|
655
|
-
if (keys.length > 0) findings.push({
|
|
656
|
-
code: "PD037",
|
|
657
|
-
severity: "error",
|
|
658
|
-
message: rowConditionMessage(found, keys),
|
|
659
|
-
fix: ROW_CONDITION_FIX
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
return findings;
|
|
663
|
-
}
|
|
664
|
-
//#endregion
|
|
665
|
-
export { pd035 as C, policyOf as E, pd034 as S, pd055 as T, pd029 as _, pd004 as a, pd032 as b, pd018 as c, pd021 as d, pd023 as f, pd027 as g, pd026 as h, pd003 as i, pd019 as l, pd025 as m, collectedOf as n, pd016 as o, pd024 as p, pd002 as r, pd017 as s, DEFAULT_SENSITIVE_ACTIONS as t, pd020 as u, pd030 as v, pd037 as w, pd033 as x, pd031 as y };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
//#region src/core/duration.ts
|
|
2
|
-
/**
|
|
3
|
-
* Parses a duration string (`'30s'`, `'15m'`, `'4h'`, `'7d'`, `'2w'`) into
|
|
4
|
-
* whole seconds. Fail-closed: a malformed or non-positive duration is
|
|
5
|
-
* `undefined`, and every caller treats that as "no bound", never a default.
|
|
6
|
-
*/
|
|
7
|
-
const UNITS = {
|
|
8
|
-
s: 1,
|
|
9
|
-
m: 60,
|
|
10
|
-
h: 3600,
|
|
11
|
-
d: 86400,
|
|
12
|
-
w: 604800
|
|
13
|
-
};
|
|
14
|
-
function parseDuration(input) {
|
|
15
|
-
if (typeof input === "number") return Number.isFinite(input) && input > 0 ? Math.floor(input) : void 0;
|
|
16
|
-
if (typeof input !== "string") return;
|
|
17
|
-
const match = /^(\d+)(s|m|h|d|w)$/u.exec(input.trim());
|
|
18
|
-
if (match === null) return;
|
|
19
|
-
const amount = Number(match[1]);
|
|
20
|
-
const unit = UNITS[match[2] ?? ""];
|
|
21
|
-
if (unit === void 0 || !Number.isFinite(amount) || amount <= 0) return;
|
|
22
|
-
return amount * unit;
|
|
23
|
-
}
|
|
24
|
-
//#endregion
|
|
25
|
-
export { parseDuration as t };
|