permdock 0.1.0 → 0.3.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 +106 -47
- package/dist/a2a/index.d.ts +7 -16
- package/dist/a2a/index.js +59 -98
- package/dist/adapter-context-mlWsVGGg.js +23 -0
- package/dist/ai-sdk/index.d.ts +37 -16
- package/dist/ai-sdk/index.js +30 -13
- package/dist/approvals/index.d.ts +3 -3
- package/dist/approvals/index.js +5 -4
- package/dist/{approvals-DaxY-Bdg.js → approvals-DbYAuNkG.js} +17 -11
- package/dist/approvers-DT4AVyIg.js +52 -0
- package/dist/{arazzo-CTeVuXr5.js → arazzo-BAgw9ap6.js} +2 -2
- package/dist/{arazzo-aoTkqYsJ.js → arazzo-CKwwqFWz.js} +2 -2
- package/dist/authzen/index.d.ts +4 -13
- package/dist/authzen/index.js +16 -50
- package/dist/better-auth/index.d.ts +20 -3
- package/dist/better-auth/index.js +27 -7
- package/dist/better-supabase/index.d.ts +223 -0
- package/dist/better-supabase/index.js +648 -0
- package/dist/bind-C_ob3LKa.d.ts +25 -0
- package/dist/bind-CuzGytRf.js +97 -0
- package/dist/boundary-BM8a_P6E.js +13 -0
- package/dist/boundary-BmHxVH1J.d.ts +15 -0
- package/dist/canonical-json-DemiK4Vp.js +26 -0
- package/dist/{capability-BDG_nkxt.d.ts → capability-2kYTMWDv.d.ts} +2 -2
- package/dist/{capability-B68OFnZx.js → capability-4qPdO9gk.js} +7 -5
- package/dist/catalog/index.d.ts +1 -1
- package/dist/catalog/index.js +1 -1
- package/dist/catalog-CRW5Mx_B.js +2 -0
- package/dist/{catalog-H-vFGwWK.js → catalog-DWF5cYqB.js} +4 -4
- package/dist/{catalog-B0E6bggc.js → catalog-dFZdWCGN.js} +2 -2
- package/dist/{catalog-doc-BSo_Q_-6.js → catalog-doc-DdGm82XT.js} +20 -32
- package/dist/claude-agent/index.d.ts +5 -14
- package/dist/claude-agent/index.js +4 -10
- package/dist/clerk/index.d.ts +12 -3
- package/dist/clerk/index.js +26 -5
- package/dist/cli/bin.js +1 -1
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +2 -2
- package/dist/clients-C7zLFuWT.d.ts +12 -0
- package/dist/clients-DjU5ABMy.js +23 -0
- package/dist/cloud/index.d.ts +4 -5
- package/dist/cloud/index.js +20 -6
- package/dist/{cloud-BNQTrmrr.js → cloud-CB_ELYuX.js} +2 -2
- package/dist/{cloud-Cuxr6Czw.js → cloud-DWLXO2af.js} +7 -6
- package/dist/collect-DClJsheJ.js +83 -0
- package/dist/{collect-O-tOtbnk.js → collect-DSTE3ml9.js} +194 -42
- package/dist/collect-DSWOk19R.js +2 -0
- package/dist/{commands-BMh_Etm2.js → commands-DSxCqG9A.js} +16 -12
- package/dist/compile/index.d.ts +3 -0
- package/dist/compile/index.js +2 -0
- package/dist/{compile-D22iwvuV.js → compile-Ba4blROR.js} +85 -30
- package/dist/compile-BkRyBDBw.d.ts +94 -0
- package/dist/config-BJiM-xAm.js +157 -0
- package/dist/config-Dnszbv-6.js +36 -0
- package/dist/config-report-DMvWKUxL.js +44 -0
- package/dist/{connection-JvqwHODC.js → connection-CU8MQxRi.js} +1 -1
- package/dist/{context-CKEAabd7.js → context-Bcy85rGi.js} +36 -27
- package/dist/convex/index.d.ts +9 -4
- package/dist/convex/index.js +14 -4
- package/dist/create-B1d519XK.d.ts +245 -0
- package/dist/create-CMwIl-w2.js +253 -0
- package/dist/{credential-B_rkUNlY.js → credential-8P81ff4u.js} +26 -46
- package/dist/delegation-D8pUEuce.js +103 -0
- package/dist/{describe-Bt1YD5uS.js → describe-B_gVZEVi.js} +10 -15
- package/dist/{describe-DernyItf.d.ts → describe-DMYiCjJV.d.ts} +9 -10
- package/dist/{diff-x5Il8LVa.js → diff-2VaeChzX.js} +44 -11
- package/dist/{diff-BUzf5Poi.js → diff-DBIhz_f2.js} +2 -2
- package/dist/{doctor-Bqo6FwUa.js → doctor-BwCAMLx_.js} +2 -2
- package/dist/doctor-collect-CHk6XWOA.js +665 -0
- package/dist/doctor-igIiM_Hl.js +1194 -0
- package/dist/drizzle/index.d.ts +4 -3
- package/dist/drizzle/index.js +3 -3
- package/dist/elysia/index.d.ts +6 -28
- package/dist/elysia/index.js +16 -60
- package/dist/{errors-DSMnAVNa.js → errors-CWfoNg9N.js} +8 -4
- package/dist/{errors-Iy71s7Oj.js → errors-Cz5zn0mW.js} +17 -71
- package/dist/{errors-DbZ1YOnb.d.ts → errors-DPdqI50v.d.ts} +8 -21
- package/dist/{errors-m3u9TmDu.js → errors-DRnGZHzF.js} +4 -1
- package/dist/evaluation-items-CfCCejQd.js +40 -0
- package/dist/{evaluations-DsAU9ppl.js → evaluations-tz6D9A2G.js} +28 -46
- package/dist/eve/index.d.ts +6 -15
- package/dist/eve/index.js +7 -12
- package/dist/expiry-BoBJ8Tvc.js +7 -0
- package/dist/express/index.d.ts +6 -29
- package/dist/express/index.js +28 -58
- package/dist/fastify/index.d.ts +6 -29
- package/dist/fastify/index.js +16 -65
- package/dist/fields-BMl1RxoX.js +26 -0
- package/dist/{files-B_wAGYmt.js → files-DWUN9PzI.js} +5 -1
- package/dist/{fixtures-Cvaw0gDG.js → fixtures-ht28Cplr.js} +5 -2
- package/dist/{freeze-y1_jQL4v.js → freeze-CrU8nQeX.js} +31 -2
- package/dist/{from-snapshot-BMGnhmgv.js → from-snapshot-CTLijvdm.js} +66 -48
- package/dist/{grantee-Bv04_Vzf.js → grantee-Cv5Sogfv.js} +88 -7
- package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
- package/dist/{headers-B5RRv3Xm.js → headers-BZSDieNT.js} +1 -1
- package/dist/{headers-C8SHQccD.d.ts → headers-Cf-zWvsO.d.ts} +1 -1
- package/dist/helpers-H_KARDVC.js +421 -0
- package/dist/hono/index.d.ts +6 -28
- package/dist/hono/index.js +11 -43
- package/dist/{hosted-BwKQ1BTA.js → hosted-DJQw46hn.js} +6 -5
- package/dist/{http-GgVApX1k.js → http-BIhmLfCc.js} +4 -20
- package/dist/http-SO7qGttf.js +44 -0
- package/dist/ids-DC4V4CFu.js +18 -0
- package/dist/index-0nNqHspG.d.ts +6 -0
- package/dist/{index-xIxJLwOQ.d.ts → index-BNc7Wer_.d.ts} +75 -7
- package/dist/{index-CltcQ4Bf.d.ts → index-C7Tw7MaW.d.ts} +68 -5
- package/dist/{index-LF_hS-yn.d.ts → index-C8z4RjQV.d.ts} +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.js +22 -17
- package/dist/instance-options-Dhhcnm3y.js +22 -0
- package/dist/instance-options-jARdwfPN.d.ts +11 -0
- package/dist/{parse-DPfIvFMU.js → json-schema-BsAflUGW.js} +28 -57
- package/dist/jwt/index.d.ts +10 -6
- package/dist/jwt/index.js +32 -13
- package/dist/kernel-_RRHmnMY.js +208 -0
- package/dist/kysely/index.d.ts +4 -3
- package/dist/kysely/index.js +3 -3
- package/dist/live-options-H2eG8dfJ.js +60 -0
- package/dist/{load-BZ24CpZP.js → load-DhWEB9P1.js} +16 -10
- package/dist/load-DwJUafYN.js +2 -0
- package/dist/manifest-iaoBXHKc.js +783 -0
- package/dist/manifest-uDS9y5de.d.ts +206 -0
- package/dist/{map-DowSO96j.js → map-AcxK9o_D.js} +4 -15
- package/dist/{map-claims-B_6I1Rn-.js → map-claims-Z4QZOiFF.js} +13 -4
- package/dist/map-error-pgUWNNtG.js +23 -0
- package/dist/may-use-DndQ5tQ-.js +77 -0
- package/dist/mcp/index.d.ts +54 -22
- package/dist/mcp/index.js +218 -178
- package/dist/nest/index.d.ts +26 -31
- package/dist/nest/index.js +75 -84
- package/dist/next/client.d.ts +7 -8
- package/dist/next/client.js +11 -9
- package/dist/next/index.d.ts +30 -47
- package/dist/next/index.js +45 -60
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +32 -1
- package/dist/node/index.d.ts +9 -28
- package/dist/node/index.js +11 -43
- package/dist/openai/index.d.ts +6 -15
- package/dist/openai/index.js +7 -20
- package/dist/openapi/index.d.ts +87 -4
- package/dist/openapi/index.js +3 -3
- package/dist/{openapi-DcqM8nU7.js → openapi-BqRBvAng.js} +237 -5
- package/dist/{openapi-DWD0Uc_4.js → openapi-CqqEbHsL.js} +5 -5
- package/dist/{openapi-import-BWRUNNeW.js → openapi-import-cmwetbzw.js} +1 -1
- package/dist/{openapi-CwePaF7C.js → openapi-l0xYHkcv.js} +3 -3
- package/dist/{openapi-schema-D8j_T9tO.js → openapi-schema--ARjyfQr.js} +2 -2
- package/dist/orpc/index.d.ts +15 -28
- package/dist/orpc/index.js +74 -117
- package/dist/otel/index.d.ts +2 -2
- package/dist/parse-BuyjxhZV.js +53 -0
- package/dist/parse-local-manifest-BrMozJCo.js +36 -0
- package/dist/parse-local-manifest-JLnaBH0S.d.ts +10 -0
- package/dist/pdp/index.d.ts +2 -2
- package/dist/pdp/index.js +14 -127
- package/dist/{permdock-yoZ7EjxX.js → permdock-CbgvLnuo.js} +672 -149
- package/dist/{permissions-B8vCg_bI.d.ts → permissions-CDgvKG5L.d.ts} +2 -2
- package/dist/{permissions-DC7GROPA.js → permissions-DVoF6dMt.js} +77 -15
- package/dist/{permissions-B4apnahQ.d.ts → permissions-DttnqqxC.d.ts} +34 -5
- package/dist/{permissions-CofRqesP.js → permissions-RJrovw98.js} +3 -3
- package/dist/{pins-CqE1jZuF.js → pins-8ILTftC9.js} +2 -2
- package/dist/{policy-Cq2fB8Q5.d.ts → policy-D2W7uv19.d.ts} +2 -2
- package/dist/{policy-CInmNGkM.d.ts → policy-IB6yxpC3.d.ts} +351 -42
- package/dist/{policy-ANp36PnI.js → policy-xyWg7QdR.js} +173 -22
- package/dist/powersync-BylawD_U.js +540 -0
- package/dist/powersync-DliZK_-y.js +62 -0
- package/dist/powersync-e_AZrKbg.js +2 -0
- package/dist/prisma/index.d.ts +3 -2
- package/dist/prisma/index.js +45 -20
- package/dist/{problem-Cgp9-KZA.js → problem-B43ztKIm.js} +74 -109
- package/dist/problem-details-DX075l9V.d.ts +7 -0
- package/dist/problem-details-_AMOYz-w.js +144 -0
- package/dist/{protected-BuPAycJT.d.ts → protected-BdnIEFkY.d.ts} +5 -4
- package/dist/protected-utU-SLuy.js +100 -0
- package/dist/protected-xAr24FEC.d.ts +40 -0
- package/dist/provider-CSQd7m92.js +52 -0
- package/dist/{provider-wTAUda2v.d.ts → provider-DZY281jO.d.ts} +1 -1
- package/dist/provider-store-Cfbvo4DE.js +43 -0
- package/dist/react/index.d.ts +7 -5
- package/dist/react/index.js +5 -4
- package/dist/react/provider-client.d.ts +1 -1
- package/dist/react/provider-client.js +1 -1
- package/dist/react-native/index.d.ts +166 -10
- package/dist/react-native/index.js +607 -85
- package/dist/{refs-ChLSxbST.js → refs-KYb4ntaz.js} +4 -3
- package/dist/{relations-r4soIFZB.js → relations-cjOL01hZ.js} +110 -31
- package/dist/replay-BsOyTrdV.js +28 -0
- package/dist/replay-CYyiLiwO.d.ts +5 -0
- package/dist/resource-ref-CaS9yVPi.js +20 -0
- package/dist/revocations-Bhr0aMIC.js +27 -0
- package/dist/{rls-BOFU3chG.js → rls-B4ur8nKQ.js} +8 -3
- package/dist/rls-DQtdgTHB.js +2521 -0
- package/dist/rls-fields-74oZPXWL.js +3582 -0
- package/dist/{rls-graph-DxQ39PJj.js → rls-graph-CHwx0V8q.js} +100 -36
- package/dist/{rls-import-CXV6LBlS.js → rls-import-BTFVk3jH.js} +7 -6
- package/dist/{rls-migrate-DrFPbf8p.js → rls-migrate-CN4TlJTO.js} +6 -5
- package/dist/rls-ownership-RuFqaqGz.js +843 -0
- package/dist/rls-shared-Cewd_-zI.js +495 -0
- package/dist/rls-verify-CVQTHTh5.js +746 -0
- package/dist/{row-check-BajTgQZ-.d.ts → row-check-Dt35czLy.d.ts} +12 -15
- package/dist/row-conditions-h2HythXQ.js +27 -0
- package/dist/rpc-DL9Sqvb1.js +89 -0
- package/dist/{run-CJ6UvS3a.js → run-DKDbM4Du.js} +31 -12
- package/dist/runtime-CB8gQFvS.js +11 -0
- package/dist/{saas-BRrZzJkM.js → saas-DhpJjnBA.js} +17 -7
- package/dist/{schema-P8yoma__.js → schema-D3MnDMxa.js} +8 -4
- package/dist/scim/index.d.ts +1 -1
- package/dist/scim/index.js +1 -1
- package/dist/{scim-9NFa0XVZ.js → scim-BFGBBAqR.js} +1 -1
- package/dist/{scopes-cKVp_WTw.js → scopes-CVdPrWN-.js} +35 -8
- package/dist/server/index.d.ts +22 -11
- package/dist/server/index.js +11 -8
- package/dist/{credentials-BgRX3WEg.js → server-DlZ28Oz5.js} +1 -1
- package/dist/shared-DRu8VFVM.js +123 -0
- package/dist/{sink-Cfr9-7YC.d.ts → sink-B1fZzIMf.d.ts} +1 -1
- package/dist/skills-Biq5uup3.js +192 -0
- package/dist/{skills-C_lpV4Jx.js → skills-Bx-U0irG.js} +10 -4
- package/dist/{snapshot-DE8dE_hz.js → snapshot-Enxd0n-s.js} +138 -214
- package/dist/snapshot-cache-B-LxUahj.d.ts +45 -0
- package/dist/snapshot-cache-D6jLelln.js +44 -0
- package/dist/solid/index.d.ts +39 -9
- package/dist/solid/index.js +76 -85
- package/dist/sources-4p0-4xQm.js +545 -0
- package/dist/sources-BdOYLw9j.d.ts +192 -0
- package/dist/{sql-Bll1d7y0.js → sql-xdg5f4Fi.js} +6 -1
- package/dist/{src-CTNT-PBW.js → src-BDwEZWrZ.js} +149 -11
- package/dist/ssf/index.d.ts +3 -2
- package/dist/ssf/index.js +3 -29
- package/dist/store-DMAWwAJV.js +371 -0
- package/dist/{store-Bq90395i.d.ts → store-jOBYpiXC.d.ts} +13 -4
- package/dist/store-options-ByhZq1jV.js +716 -0
- package/dist/{stores-CkG2HrSg.js → stores-BT2pSCub.js} +10 -63
- package/dist/{stores-CvOnu_2T.d.ts → stores-C0IMQrGI.d.ts} +20 -9
- package/dist/{stream-BhMfZOwr.d.ts → stream-D1RXubw2.d.ts} +2 -2
- package/dist/{stream-Q_xlB6Ko.js → stream-DDpvynSB.js} +16 -2
- package/dist/subject-settings-BwBmCdTR.js +128 -0
- package/dist/supabase/index.d.ts +133 -6
- package/dist/supabase/index.js +4 -3
- package/dist/supabase/middleware.d.ts +32 -27
- package/dist/supabase/middleware.js +56 -22
- package/dist/{supabase-D8UlBA7Z.js → supabase-Boqb9a_Y.js} +3 -3
- package/dist/{supabase-DTxGtYdi.js → supabase-C0qESOa-.js} +347 -367
- package/dist/supabase-config-BpPXt3x1.js +472 -0
- package/dist/supabase-hook-6sYLXg_u.js +2 -0
- package/dist/{supabase-hook-D_OqGb_V.js → supabase-hook-CSLQ4zJ3.js} +1037 -705
- package/dist/supautils-Cn4R4cJ4.js +91 -0
- package/dist/svelte/PermissionBoundary.svelte +37 -0
- package/dist/svelte/Protected.svelte +8 -2
- package/dist/svelte/index.d.ts +9 -6
- package/dist/svelte/index.js +61 -7
- package/dist/svelte/runtime.d.ts +4 -3
- package/dist/svelte/runtime.js +4 -3
- package/dist/svelte/source.d.ts +9 -6
- package/dist/svelte/source.js +7 -4
- package/dist/terminal/index.d.ts +6 -14
- package/dist/terminal/index.js +44 -32
- package/dist/testing/index.d.ts +105 -16
- package/dist/testing/index.js +504 -40
- package/dist/testing/saas/index.d.ts +4 -4
- package/dist/testing/saas/index.js +2 -2
- package/dist/testing/saas/permissions.d.ts +1 -1
- package/dist/testing/saas/permissions.js +1 -1
- package/dist/token-CIWxJOCh.js +50 -0
- package/dist/trpc/index.d.ts +7 -26
- package/dist/trpc/index.js +17 -100
- package/dist/types-BnIEz1sU.d.ts +48 -0
- package/dist/{types-CxquUByI.d.ts → types-Bvc4oWT6.d.ts} +1 -1
- package/dist/{sources-DOpW5Ila.d.ts → types-C97IskBw.d.ts} +86 -127
- package/dist/types-CKNSyIf_.d.ts +52 -0
- package/dist/types-Cq_H8N_X.d.ts +197 -0
- package/dist/{types-D6Z6-rKJ.d.ts → types-DbjRN55U.d.ts} +273 -22
- package/dist/{types-BBK-exvJ.d.ts → types-Dnemwd77.d.ts} +7 -1
- package/dist/{types-BvBk1wgn.d.ts → types-DxiCGmmd.d.ts} +5 -3
- package/dist/{types-B9dmiiab.d.ts → types-QCuYJh4q.d.ts} +1 -1
- package/dist/{types-B8w5PFtS.d.ts → types-aqOHTHcp.d.ts} +17 -1
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +10 -9
- package/dist/usage-DorAJiU_.js +2 -0
- package/dist/{usage-1ozMubLY.js → usage-GTixvDDU.js} +2 -2
- package/dist/{usage-CUnK6Ou9.js → usage-ItS7nLcl.js} +225 -62
- package/dist/validation-error-Ba264OaJ.d.ts +26 -0
- package/dist/validation-error-CnjZ4t92.js +33 -0
- package/dist/{validity-D0uRmJKJ.js → validity-uOp8UpYn.js} +57 -36
- package/dist/{verifier-B90agnhl.js → verifier-BxBo6I44.js} +10 -5
- package/dist/version-BvacVTZR.js +17 -0
- package/dist/views-Soe7bGSC.js +95 -0
- package/dist/{vocabulary-Dk0fs-Jk.d.ts → vocabulary-DA8a8zif.d.ts} +1 -1
- package/dist/vue/index.d.ts +35 -13
- package/dist/vue/index.js +86 -93
- package/dist/watch-BwxLTYMZ.js +2 -0
- package/dist/watch-DVBJ9cBq.js +128 -0
- package/dist/webmcp/index.d.ts +2 -2
- package/dist/webmcp/index.js +7 -13
- package/package.json +62 -36
- package/schemas/approval-request-v1.json +175 -0
- package/schemas/catalog-v1.json +29 -1
- package/schemas/supabase-claims-v1.json +6 -1
- package/schemas/supabase-manifest-v1.json +150 -6
- package/skills/permdock/SKILL.md +7 -7
- package/skills/permdock-agents/SKILL.md +5 -5
- package/skills/permdock-agents/references/runtimes.md +12 -10
- package/skills/permdock-approvals/SKILL.md +4 -4
- package/skills/permdock-approvals/references/stores-and-resume.md +15 -4
- package/skills/permdock-audit/SKILL.md +3 -3
- package/skills/permdock-credentials/SKILL.md +4 -4
- package/skills/permdock-credentials/references/tokens-keys-links.md +7 -2
- package/skills/permdock-data/SKILL.md +4 -4
- package/skills/permdock-data/references/queries-and-rls.md +14 -6
- package/skills/permdock-data/references/relationships.md +5 -3
- package/skills/permdock-tenancy/SKILL.md +9 -6
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +14 -8
- package/skills/permdock-wire/SKILL.md +4 -4
- package/skills/permdock-wire/references/adapters.md +42 -30
- package/skills/permdock-wire/references/policy-options.md +5 -3
- package/dist/approvers-aH0PJkmf.js +0 -20
- package/dist/catalog-idsHc0vo.js +0 -2
- package/dist/collect-B7_TIfmg.js +0 -49
- package/dist/collect-fRPAQIWb.js +0 -2
- package/dist/compile-CQbvyIBr.d.ts +0 -30
- package/dist/config-BPYmjTOp.js +0 -26
- package/dist/context-gtAwAILx.js +0 -6
- package/dist/create-BKF3dgFk.d.ts +0 -162
- package/dist/create-CSkhDU9T.js +0 -222
- package/dist/doctor-BGle8Gqi.js +0 -1314
- package/dist/helpers-DnSOrhB9.js +0 -682
- package/dist/index-fG6NSXlc.d.ts +0 -9
- package/dist/kernel-YOGCWNLf.js +0 -211
- package/dist/load-QOOm1z70.js +0 -2
- package/dist/manifest-DDQbC6K0.d.ts +0 -118
- package/dist/map-error-RJ3ZsUyA.js +0 -16
- package/dist/may-use-CnFEjVEp.js +0 -37
- package/dist/pg-4GJWDUxG.js +0 -953
- package/dist/plugin-4gr7IxFJ.js +0 -65
- package/dist/protected-B4K3BKoX.js +0 -138
- package/dist/protected-wY7nXhY9.d.ts +0 -23
- package/dist/provider-_wx46HpB.js +0 -48
- package/dist/rls-CJVja9Ww.js +0 -2119
- package/dist/rls-helpers-BxRuif0l.js +0 -1346
- package/dist/runtime-DP9ttFh1.js +0 -27
- package/dist/skills-Dx3QLnMY.js +0 -110
- package/dist/source-DoBBYJi2.js +0 -6
- package/dist/sources-DVHM3Mwq.js +0 -284
- package/dist/store-C6hFW6ta.js +0 -508
- package/dist/subject-settings-xt7V845g.js +0 -82
- package/dist/supabase-hook-DW-xP4hU.js +0 -2
- package/dist/types-DbWdEfcm.d.ts +0 -87
- package/dist/types-bva3i4Gf.d.ts +0 -98
- package/dist/types-i4BAOvdb.d.ts +0 -97
- package/dist/usage-PyEor6GA.js +0 -2
- package/dist/version-CnSh33Fj.js +0 -16
package/dist/testing/index.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as principal } from "../refs-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { n as parseSnapshot } from "../snapshot-
|
|
8
|
-
import { i as parsePolicyDocument, r as mergeHostedGrants } from "../hosted-
|
|
9
|
-
import {
|
|
1
|
+
import { _ as listPermissions, b as resource, n as definePermissions } from "../permissions-DVoF6dMt.js";
|
|
2
|
+
import { r as principal } from "../refs-KYb4ntaz.js";
|
|
3
|
+
import { _ as memoryLimitStore, a as definePolicy, m as role, t as allow } from "../policy-xyWg7QdR.js";
|
|
4
|
+
import { _ as memoryRoleSource, u as snapshotFor } from "../src-BDwEZWrZ.js";
|
|
5
|
+
import { t as memoryRevocationFeed } from "../revocations-Bhr0aMIC.js";
|
|
6
|
+
import { a as normalizeMemberships, d as scopeList } from "../scopes-CVdPrWN-.js";
|
|
7
|
+
import { n as parseSnapshot, p as evaluateCondition } from "../snapshot-Enxd0n-s.js";
|
|
8
|
+
import { i as parsePolicyDocument, r as mergeHostedGrants } from "../hosted-DJQw46hn.js";
|
|
9
|
+
import { E as approvalPoliciesFor, b as validateCustomRole, t as createPermDock, v as membershipsClaim } from "../permdock-CbgvLnuo.js";
|
|
10
10
|
import { t as byCodePoint } from "../compare-pfyVnBjE.js";
|
|
11
|
-
import { n as fromSnapshot } from "../from-snapshot-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import { n as fromSnapshot } from "../from-snapshot-CTLijvdm.js";
|
|
12
|
+
import { o as parseCredential } from "../credential-8P81ff4u.js";
|
|
13
|
+
import { o as problemFromDecision } from "../problem-B43ztKIm.js";
|
|
14
|
+
import { l as APPROVAL_HEADER, r as memoryApprovalStore } from "../store-DMAWwAJV.js";
|
|
15
|
+
import { o as resolveApproval } from "../helpers-H_KARDVC.js";
|
|
16
|
+
import { a as parseApiKey } from "../server-DlZ28Oz5.js";
|
|
17
|
+
import { S as sha256Hex, n as directoryMembershipSource, r as scimHandler } from "../scim-BFGBBAqR.js";
|
|
15
18
|
import { t as supabaseMembershipsBudget } from "../budget-NbEtbJC_.js";
|
|
16
|
-
import { r as quoteSqlIdent, t as SQL_IDENT } from "../sql-
|
|
17
|
-
import { i as saasPermissions } from "../permissions-
|
|
18
|
-
import { C as saasOrg, E as saasSeed, S as saasMemberships, a as saasProject, g as verifySaasSession, h as signSaasToken, k as saasPolicy, t as saasDoc, w as saasPrincipal, x as saasCustomRoles } from "../saas-
|
|
19
|
+
import { a as quoteSqlTable, r as quoteSqlIdent, t as SQL_IDENT } from "../sql-xdg5f4Fi.js";
|
|
20
|
+
import { i as saasPermissions } from "../permissions-RJrovw98.js";
|
|
21
|
+
import { C as saasOrg, E as saasSeed, S as saasMemberships, a as saasProject, g as verifySaasSession, h as signSaasToken, k as saasPolicy, t as saasDoc, w as saasPrincipal, x as saasCustomRoles } from "../saas-DhpJjnBA.js";
|
|
19
22
|
import { afterAll, beforeAll, describe, expect, expectTypeOf, it, vi } from "vitest";
|
|
20
23
|
//#region src/testing/describe-policy.ts
|
|
21
24
|
function isOutcomeCell(value) {
|
|
@@ -139,7 +142,7 @@ function subjectSettings(dialect, subject, gucPrefix, tenantClaim, roleClaim, cu
|
|
|
139
142
|
* a base table whose restricted columns are revoked does not reject it.
|
|
140
143
|
*/
|
|
141
144
|
function statementSql(action, table, keyOnly) {
|
|
142
|
-
const quoted =
|
|
145
|
+
const quoted = quoteSqlTable(table);
|
|
143
146
|
const id = quoteSqlIdent("id");
|
|
144
147
|
const back = keyOnly ? id : "*";
|
|
145
148
|
switch (action) {
|
|
@@ -163,11 +166,11 @@ function isRead(action) {
|
|
|
163
166
|
async function viewColumns(query, table, key) {
|
|
164
167
|
const id = quoteSqlIdent("id");
|
|
165
168
|
await query("savepoint permdock_fields");
|
|
166
|
-
const view = await query(`select * from ${
|
|
169
|
+
const view = await query(`select * from ${quoteSqlTable(`${table}_visible`)} where ${id} = $1`, [key]);
|
|
167
170
|
if (view.code === void 0) return valued(view.rows[0]);
|
|
168
171
|
await query("rollback to savepoint permdock_fields");
|
|
169
172
|
if (view.code !== "42P01") return view.code;
|
|
170
|
-
const base = await query(`select * from ${
|
|
173
|
+
const base = await query(`select * from ${quoteSqlTable(table)} where ${id} = $1`, [key]);
|
|
171
174
|
return base.code ?? valued(base.rows[0]);
|
|
172
175
|
}
|
|
173
176
|
function dbOutcome(result) {
|
|
@@ -616,6 +619,63 @@ function testClientStore(name, createStore) {
|
|
|
616
619
|
await settle();
|
|
617
620
|
expect(net.calls).toHaveLength(2);
|
|
618
621
|
});
|
|
622
|
+
it("answers a row edited in place once the task that read it ends", async () => {
|
|
623
|
+
const net = recorder(unreachable);
|
|
624
|
+
const store = createStore({
|
|
625
|
+
snapshot: snapshotOf("bob", "acme"),
|
|
626
|
+
tenant: "acme",
|
|
627
|
+
fetch: net.fetch
|
|
628
|
+
});
|
|
629
|
+
const row = {
|
|
630
|
+
...acmeProject,
|
|
631
|
+
ownerId: "bob"
|
|
632
|
+
};
|
|
633
|
+
expect(store.get().status(p.project.update, row)).toBe("ready");
|
|
634
|
+
expect(store.get().can(p.project.update, row)).toBe(true);
|
|
635
|
+
row.ownerId = "alice";
|
|
636
|
+
await settle();
|
|
637
|
+
expect(store.get().can(p.project.update, row)).toBe(false);
|
|
638
|
+
});
|
|
639
|
+
it("answers a check on a row that throws as denied, without throwing", () => {
|
|
640
|
+
const net = recorder(unreachable);
|
|
641
|
+
const store = createStore({
|
|
642
|
+
snapshot: snapshotOf("bob", "acme"),
|
|
643
|
+
tenant: "acme",
|
|
644
|
+
fetch: net.fetch
|
|
645
|
+
});
|
|
646
|
+
const hostile = new Proxy({}, { get() {
|
|
647
|
+
throw new Error("hostile row");
|
|
648
|
+
} });
|
|
649
|
+
expect(store.get().status(p.project.update, hostile)).not.toBe("pending");
|
|
650
|
+
expect(store.get().can(p.project.update, hostile)).toBe(false);
|
|
651
|
+
});
|
|
652
|
+
it("notifies every subscriber of a logout when one of them throws", () => {
|
|
653
|
+
const reported = vi.fn();
|
|
654
|
+
vi.stubGlobal("reportError", reported);
|
|
655
|
+
try {
|
|
656
|
+
const net = recorder(unreachable);
|
|
657
|
+
const store = createStore({
|
|
658
|
+
snapshot: snapshotOf("bob", "acme"),
|
|
659
|
+
tenant: "acme",
|
|
660
|
+
fetch: net.fetch
|
|
661
|
+
});
|
|
662
|
+
let after = 0;
|
|
663
|
+
const offThrowing = store.get().subscribe(() => {
|
|
664
|
+
throw new Error("subscriber failed");
|
|
665
|
+
});
|
|
666
|
+
const offCounting = store.get().subscribe(() => {
|
|
667
|
+
after += 1;
|
|
668
|
+
});
|
|
669
|
+
store.get().clear();
|
|
670
|
+
expect(after).toBe(1);
|
|
671
|
+
expect(reported).toHaveBeenCalled();
|
|
672
|
+
expect(store.get().can(p.project.read, acmeProject)).toBe(false);
|
|
673
|
+
offThrowing();
|
|
674
|
+
offCounting();
|
|
675
|
+
} finally {
|
|
676
|
+
vi.unstubAllGlobals();
|
|
677
|
+
}
|
|
678
|
+
});
|
|
619
679
|
it("does not notify subscribers synchronously from a status read", () => {
|
|
620
680
|
const net = recorder(() => json({ evaluations: [] }));
|
|
621
681
|
const store = createStore({
|
|
@@ -684,7 +744,7 @@ async function* ticks(org, signal) {
|
|
|
684
744
|
function demotionKey(user, org) {
|
|
685
745
|
return JSON.stringify([user, org]);
|
|
686
746
|
}
|
|
687
|
-
function createDomain() {
|
|
747
|
+
function createDomain$1() {
|
|
688
748
|
const demoted = /* @__PURE__ */ new Set();
|
|
689
749
|
const principalOf = (sub, path) => {
|
|
690
750
|
const principal = saasPrincipal(sub, orgOf(path));
|
|
@@ -927,7 +987,7 @@ function testHttpAdapter(options) {
|
|
|
927
987
|
it.skipIf(reason !== void 0)(reason === void 0 ? title : `${title} (${reason})`, run, timeout);
|
|
928
988
|
};
|
|
929
989
|
describe(`${options.name}: real-life HTTP scenarios`, () => {
|
|
930
|
-
const domain = createDomain();
|
|
990
|
+
const domain = createDomain$1();
|
|
931
991
|
const tokens = /* @__PURE__ */ new Map();
|
|
932
992
|
let mounted;
|
|
933
993
|
beforeAll(async () => {
|
|
@@ -1096,14 +1156,24 @@ function testHttpAdapter(options) {
|
|
|
1096
1156
|
}
|
|
1097
1157
|
})).status).toBe(403);
|
|
1098
1158
|
});
|
|
1099
|
-
scenario("assert", "maps assert inside a handler to
|
|
1159
|
+
scenario("assert", "maps assert inside a handler to the Problem protect sends", async () => {
|
|
1100
1160
|
const denied = await send("bob", {
|
|
1101
1161
|
op: "project.delete",
|
|
1102
1162
|
org: "acme",
|
|
1103
1163
|
id: "p2"
|
|
1104
1164
|
});
|
|
1105
1165
|
expect(denied.status).toBe(403);
|
|
1106
|
-
expect(field(denied.body, "type")).toBe("https://permdock.
|
|
1166
|
+
expect(field(denied.body, "type")).toBe("https://permdock.com/problems/denied");
|
|
1167
|
+
const bob = await createPermDock(saasPolicy, saasPrincipal("bob", "acme"), { tenant: "acme" });
|
|
1168
|
+
const permission = saasPolicy.permissions.project.delete;
|
|
1169
|
+
const fromProtect = await readResult(problemFromDecision(bob.decide(permission, project$1("p2")), permission, bob.subject));
|
|
1170
|
+
expect(denied.status).toBe(fromProtect.status);
|
|
1171
|
+
for (const key of [
|
|
1172
|
+
"type",
|
|
1173
|
+
"title",
|
|
1174
|
+
"permission",
|
|
1175
|
+
"denials"
|
|
1176
|
+
]) expect(field(denied.body, key)).toEqual(field(fromProtect.body, key));
|
|
1107
1177
|
expect((await send("bob", {
|
|
1108
1178
|
op: "project.delete",
|
|
1109
1179
|
org: "acme",
|
|
@@ -1121,7 +1191,7 @@ function testHttpAdapter(options) {
|
|
|
1121
1191
|
org: "acme"
|
|
1122
1192
|
});
|
|
1123
1193
|
expect(asked.status).toBe(403);
|
|
1124
|
-
expect(field(asked.body, "type")).toBe("https://permdock.
|
|
1194
|
+
expect(field(asked.body, "type")).toBe("https://permdock.com/problems/approval-required");
|
|
1125
1195
|
const token = field(asked.body, "token");
|
|
1126
1196
|
expect(typeof token).toBe("string");
|
|
1127
1197
|
await resolveApproval(domain.store, String(token), {
|
|
@@ -1230,7 +1300,7 @@ function testHttpAdapter(options) {
|
|
|
1230
1300
|
});
|
|
1231
1301
|
const end = await untilEnd(stream);
|
|
1232
1302
|
expect(end.problem).toMatchObject({
|
|
1233
|
-
type: "https://permdock.
|
|
1303
|
+
type: "https://permdock.com/problems/unauthenticated",
|
|
1234
1304
|
status: 401,
|
|
1235
1305
|
detail: "session-revoked"
|
|
1236
1306
|
});
|
|
@@ -1252,7 +1322,7 @@ function testHttpAdapter(options) {
|
|
|
1252
1322
|
});
|
|
1253
1323
|
const end = await untilEnd(stream);
|
|
1254
1324
|
expect(end.problem).toMatchObject({
|
|
1255
|
-
type: "https://permdock.
|
|
1325
|
+
type: "https://permdock.com/problems/denied",
|
|
1256
1326
|
status: 403
|
|
1257
1327
|
});
|
|
1258
1328
|
expect(end.ended).toBe(true);
|
|
@@ -1290,7 +1360,7 @@ function testHttpAdapter(options) {
|
|
|
1290
1360
|
expect((await stream.next())?.event).toBe("message");
|
|
1291
1361
|
const end = await untilEnd(stream);
|
|
1292
1362
|
expect(end.problem).toMatchObject({
|
|
1293
|
-
type: "https://permdock.
|
|
1363
|
+
type: "https://permdock.com/problems/unauthenticated",
|
|
1294
1364
|
detail: "expired"
|
|
1295
1365
|
});
|
|
1296
1366
|
expect(end.ended).toBe(true);
|
|
@@ -1301,6 +1371,148 @@ function testHttpAdapter(options) {
|
|
|
1301
1371
|
});
|
|
1302
1372
|
}
|
|
1303
1373
|
//#endregion
|
|
1374
|
+
//#region src/testing/agent-adapter.ts
|
|
1375
|
+
/** The user whose subject resolver throws. */
|
|
1376
|
+
const AGENT_THROWING_USER = "throws";
|
|
1377
|
+
/** The project id whose loader throws. */
|
|
1378
|
+
const AGENT_THROWING_ROW = "throws";
|
|
1379
|
+
const SCENARIOS = [
|
|
1380
|
+
{
|
|
1381
|
+
name: "granted",
|
|
1382
|
+
title: "grants a member reading a project in their org",
|
|
1383
|
+
call: {
|
|
1384
|
+
user: "alice",
|
|
1385
|
+
org: "acme",
|
|
1386
|
+
tool: "project_read",
|
|
1387
|
+
args: { id: "p1" }
|
|
1388
|
+
},
|
|
1389
|
+
expected: "granted"
|
|
1390
|
+
},
|
|
1391
|
+
{
|
|
1392
|
+
name: "denied",
|
|
1393
|
+
title: "denies a user with no membership",
|
|
1394
|
+
call: {
|
|
1395
|
+
user: "mallory",
|
|
1396
|
+
org: "acme",
|
|
1397
|
+
tool: "project_read",
|
|
1398
|
+
args: { id: "p1" }
|
|
1399
|
+
},
|
|
1400
|
+
expected: "denied"
|
|
1401
|
+
},
|
|
1402
|
+
{
|
|
1403
|
+
name: "cross-tenant",
|
|
1404
|
+
title: "denies a row from another org",
|
|
1405
|
+
call: {
|
|
1406
|
+
user: "alice",
|
|
1407
|
+
org: "acme",
|
|
1408
|
+
tool: "project_read",
|
|
1409
|
+
args: { id: "g1" }
|
|
1410
|
+
},
|
|
1411
|
+
expected: "denied"
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
name: "anonymous",
|
|
1415
|
+
title: "denies a call with no user",
|
|
1416
|
+
call: {
|
|
1417
|
+
user: null,
|
|
1418
|
+
org: "acme",
|
|
1419
|
+
tool: "project_read",
|
|
1420
|
+
args: { id: "p1" }
|
|
1421
|
+
},
|
|
1422
|
+
expected: "denied"
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
name: "subject-throws",
|
|
1426
|
+
title: "denies when the subject resolver throws",
|
|
1427
|
+
call: {
|
|
1428
|
+
user: AGENT_THROWING_USER,
|
|
1429
|
+
org: "acme",
|
|
1430
|
+
tool: "project_read",
|
|
1431
|
+
args: { id: "p1" }
|
|
1432
|
+
},
|
|
1433
|
+
expected: "denied"
|
|
1434
|
+
},
|
|
1435
|
+
{
|
|
1436
|
+
name: "loader-throws",
|
|
1437
|
+
title: "denies when the row loader throws",
|
|
1438
|
+
call: {
|
|
1439
|
+
user: "alice",
|
|
1440
|
+
org: "acme",
|
|
1441
|
+
tool: "project_read",
|
|
1442
|
+
args: { id: AGENT_THROWING_ROW }
|
|
1443
|
+
},
|
|
1444
|
+
expected: "denied"
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
name: "missing-row",
|
|
1448
|
+
title: "denies when the row does not exist",
|
|
1449
|
+
call: {
|
|
1450
|
+
user: "alice",
|
|
1451
|
+
org: "acme",
|
|
1452
|
+
tool: "project_read",
|
|
1453
|
+
args: { id: "missing" }
|
|
1454
|
+
},
|
|
1455
|
+
expected: "denied"
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
name: "approval-required",
|
|
1459
|
+
title: "asks for approval before revoking every API key",
|
|
1460
|
+
call: {
|
|
1461
|
+
user: "alice",
|
|
1462
|
+
org: "acme",
|
|
1463
|
+
tool: "api_keys_revoke_all",
|
|
1464
|
+
args: {}
|
|
1465
|
+
},
|
|
1466
|
+
expected: "approval-required"
|
|
1467
|
+
}
|
|
1468
|
+
];
|
|
1469
|
+
function loadProject(args) {
|
|
1470
|
+
const id = typeof args === "object" && args !== null ? args.id : void 0;
|
|
1471
|
+
if (id === "throws") throw new Error("project store unavailable");
|
|
1472
|
+
return saasSeed.projects.find((row) => row.id === id) ?? null;
|
|
1473
|
+
}
|
|
1474
|
+
function createDomain() {
|
|
1475
|
+
return {
|
|
1476
|
+
policy: saasPolicy,
|
|
1477
|
+
subject: (user, org) => {
|
|
1478
|
+
if (user === "throws") throw new Error("session store unavailable");
|
|
1479
|
+
return user === null ? null : saasPrincipal(user, org);
|
|
1480
|
+
},
|
|
1481
|
+
tools: {
|
|
1482
|
+
project_read: {
|
|
1483
|
+
permission: saasPermissions.project.read,
|
|
1484
|
+
data: loadProject
|
|
1485
|
+
},
|
|
1486
|
+
api_keys_revoke_all: { permission: saasPermissions.apiKey.revokeAll }
|
|
1487
|
+
},
|
|
1488
|
+
customRoles: memoryRoleSource(saasCustomRoles),
|
|
1489
|
+
store: memoryApprovalStore()
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Runs the same tool calls through an agent adapter: a grant, the denials an
|
|
1494
|
+
* attacker or an outage produces, and an approval. Every failure denies.
|
|
1495
|
+
*/
|
|
1496
|
+
function testAgentAdapter(options) {
|
|
1497
|
+
describe(`${options.name}: agent adapter scenarios`, () => {
|
|
1498
|
+
const domain = createDomain();
|
|
1499
|
+
let mounted;
|
|
1500
|
+
beforeAll(async () => {
|
|
1501
|
+
mounted = await options.mount(domain);
|
|
1502
|
+
});
|
|
1503
|
+
afterAll(async () => {
|
|
1504
|
+
await mounted.close?.();
|
|
1505
|
+
});
|
|
1506
|
+
const outcomeOf = (call) => mounted.call(call);
|
|
1507
|
+
for (const scenario of SCENARIOS) {
|
|
1508
|
+
const reason = options.skip?.[scenario.name];
|
|
1509
|
+
it.skipIf(reason !== void 0)(reason === void 0 ? scenario.title : `${scenario.title} (${reason})`, async () => {
|
|
1510
|
+
expect(await outcomeOf(scenario.call)).toBe(scenario.expected);
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
//#endregion
|
|
1304
1516
|
//#region src/testing/authzen.ts
|
|
1305
1517
|
function sortKey(value) {
|
|
1306
1518
|
return JSON.stringify(Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => byCodePoint(a, b))));
|
|
@@ -1592,11 +1804,12 @@ function testSubjectResolver(resolver, options) {
|
|
|
1592
1804
|
});
|
|
1593
1805
|
}
|
|
1594
1806
|
function testMembershipSource(source, options) {
|
|
1807
|
+
const query = options.tenant === void 0 ? {} : { tenant: options.tenant };
|
|
1595
1808
|
it("returns well-formed memberships and fails closed on throw", async () => {
|
|
1596
1809
|
for (const principal of options.principals) {
|
|
1597
1810
|
let memberships = [];
|
|
1598
1811
|
try {
|
|
1599
|
-
memberships = await source.membershipsFor(principal,
|
|
1812
|
+
memberships = await source.membershipsFor(principal, query);
|
|
1600
1813
|
} catch {
|
|
1601
1814
|
memberships = [];
|
|
1602
1815
|
}
|
|
@@ -1618,7 +1831,7 @@ function testMembershipSource(source, options) {
|
|
|
1618
1831
|
for (const principal of options.principals) {
|
|
1619
1832
|
let memberships = [];
|
|
1620
1833
|
try {
|
|
1621
|
-
memberships = await source.membershipsFor(principal,
|
|
1834
|
+
memberships = await source.membershipsFor(principal, query);
|
|
1622
1835
|
} catch {
|
|
1623
1836
|
continue;
|
|
1624
1837
|
}
|
|
@@ -1726,6 +1939,22 @@ function testRelationSource(source, options) {
|
|
|
1726
1939
|
expect(linked.ancestors.map((ancestor) => ancestor.id)).toEqual([id]);
|
|
1727
1940
|
}
|
|
1728
1941
|
});
|
|
1942
|
+
it("reads each object's row as an object, or null when there is none", async () => {
|
|
1943
|
+
if (source.row === void 0) return;
|
|
1944
|
+
const read = (query) => source.row?.(query);
|
|
1945
|
+
for (const object of options.objects) {
|
|
1946
|
+
const row = await read({
|
|
1947
|
+
resource: object.resource,
|
|
1948
|
+
id: object.id
|
|
1949
|
+
});
|
|
1950
|
+
expect(row === null || row === void 0 || typeof row === "object" && !Array.isArray(row)).toBe(true);
|
|
1951
|
+
}
|
|
1952
|
+
const missing = await read({
|
|
1953
|
+
resource: options.objects[0]?.resource ?? "",
|
|
1954
|
+
id: "permdock-missing-object"
|
|
1955
|
+
});
|
|
1956
|
+
expect(missing ?? null).toBeNull();
|
|
1957
|
+
});
|
|
1729
1958
|
it("answers an unknown object with nothing instead of throwing", async () => {
|
|
1730
1959
|
const first = options.objects[0];
|
|
1731
1960
|
if (first === void 0) return;
|
|
@@ -1767,6 +1996,11 @@ function testRoleSource(source, options) {
|
|
|
1767
1996
|
for (const name of assignable) expect(declared).toContain(name);
|
|
1768
1997
|
}
|
|
1769
1998
|
});
|
|
1999
|
+
const every = options.every;
|
|
2000
|
+
if (every !== void 0) it("returns every custom role of the tenant, held or not", async () => {
|
|
2001
|
+
const roles = await source.rolesFor(options.tenant, { held: [] });
|
|
2002
|
+
expect([...new Set(roles.map((role) => role.name))].toSorted()).toEqual([...new Set(every)].toSorted());
|
|
2003
|
+
});
|
|
1770
2004
|
}
|
|
1771
2005
|
function testLimitStore(store) {
|
|
1772
2006
|
it("counts down synchronously and fails closed when exhausted", async () => {
|
|
@@ -2320,6 +2554,44 @@ function testApprovalStore(store, options = {}) {
|
|
|
2320
2554
|
expect(second.resolvedBy).toBe("u_10");
|
|
2321
2555
|
expect(await store.consume("quorum-token")).not.toBeNull();
|
|
2322
2556
|
});
|
|
2557
|
+
it("resolves a vouched verdict at once, records its rule, and still refuses the requester", async () => {
|
|
2558
|
+
await store.create({
|
|
2559
|
+
...sampleApproval("vouched-token"),
|
|
2560
|
+
approvers: {
|
|
2561
|
+
by: admin,
|
|
2562
|
+
quorum: 2
|
|
2563
|
+
}
|
|
2564
|
+
});
|
|
2565
|
+
await expect(Promise.resolve().then(() => store.resolve("vouched-token", {
|
|
2566
|
+
status: "approved",
|
|
2567
|
+
by: {
|
|
2568
|
+
principal: {
|
|
2569
|
+
id: "u_1",
|
|
2570
|
+
roles: []
|
|
2571
|
+
},
|
|
2572
|
+
context: {}
|
|
2573
|
+
},
|
|
2574
|
+
vouched: "app-rule"
|
|
2575
|
+
}))).rejects.toThrow(/principal/u);
|
|
2576
|
+
const resolved = await store.resolve("vouched-token", {
|
|
2577
|
+
status: "approved",
|
|
2578
|
+
by: {
|
|
2579
|
+
principal: {
|
|
2580
|
+
id: "u_outsider",
|
|
2581
|
+
roles: []
|
|
2582
|
+
},
|
|
2583
|
+
context: {}
|
|
2584
|
+
},
|
|
2585
|
+
vouched: "app-rule"
|
|
2586
|
+
});
|
|
2587
|
+
expect(resolved.status).toBe("approved");
|
|
2588
|
+
expect(resolved.vouched).toBe("app-rule");
|
|
2589
|
+
expect(resolved.approvals).toEqual([{
|
|
2590
|
+
by: "u_outsider",
|
|
2591
|
+
at: expect.any(String),
|
|
2592
|
+
vouched: "app-rule"
|
|
2593
|
+
}]);
|
|
2594
|
+
});
|
|
2323
2595
|
it("lets one rejection end a quorum request", async () => {
|
|
2324
2596
|
await store.create({
|
|
2325
2597
|
...sampleApproval("veto-token"),
|
|
@@ -2629,7 +2901,176 @@ function testTokenSigner(signer, options) {
|
|
|
2629
2901
|
}
|
|
2630
2902
|
});
|
|
2631
2903
|
}
|
|
2904
|
+
const WHERE_ROWS = [
|
|
2905
|
+
{
|
|
2906
|
+
id: "r1",
|
|
2907
|
+
authorId: "u1",
|
|
2908
|
+
score: 5,
|
|
2909
|
+
title: "Plan 100%",
|
|
2910
|
+
archived: false,
|
|
2911
|
+
note: null
|
|
2912
|
+
},
|
|
2913
|
+
{
|
|
2914
|
+
id: "r2",
|
|
2915
|
+
authorId: "u2",
|
|
2916
|
+
score: 10,
|
|
2917
|
+
title: "plan_b",
|
|
2918
|
+
archived: true,
|
|
2919
|
+
note: "kept"
|
|
2920
|
+
},
|
|
2921
|
+
{
|
|
2922
|
+
id: "r3",
|
|
2923
|
+
authorId: null,
|
|
2924
|
+
score: null,
|
|
2925
|
+
title: null,
|
|
2926
|
+
archived: null,
|
|
2927
|
+
note: null
|
|
2928
|
+
}
|
|
2929
|
+
];
|
|
2930
|
+
const WHERE_CASES = [
|
|
2931
|
+
["eq", {
|
|
2932
|
+
op: "eq",
|
|
2933
|
+
field: "authorId",
|
|
2934
|
+
value: "u1"
|
|
2935
|
+
}],
|
|
2936
|
+
["ne", {
|
|
2937
|
+
op: "ne",
|
|
2938
|
+
field: "authorId",
|
|
2939
|
+
value: "u1"
|
|
2940
|
+
}],
|
|
2941
|
+
["eq on a boolean", {
|
|
2942
|
+
op: "eq",
|
|
2943
|
+
field: "archived",
|
|
2944
|
+
value: false
|
|
2945
|
+
}],
|
|
2946
|
+
["gt", {
|
|
2947
|
+
op: "gt",
|
|
2948
|
+
field: "score",
|
|
2949
|
+
value: 5
|
|
2950
|
+
}],
|
|
2951
|
+
["gte", {
|
|
2952
|
+
op: "gte",
|
|
2953
|
+
field: "score",
|
|
2954
|
+
value: 5
|
|
2955
|
+
}],
|
|
2956
|
+
["lt", {
|
|
2957
|
+
op: "lt",
|
|
2958
|
+
field: "score",
|
|
2959
|
+
value: 10
|
|
2960
|
+
}],
|
|
2961
|
+
["lte", {
|
|
2962
|
+
op: "lte",
|
|
2963
|
+
field: "score",
|
|
2964
|
+
value: 10
|
|
2965
|
+
}],
|
|
2966
|
+
["contains a literal %", {
|
|
2967
|
+
op: "contains",
|
|
2968
|
+
field: "title",
|
|
2969
|
+
value: "100%"
|
|
2970
|
+
}],
|
|
2971
|
+
["contains a literal _", {
|
|
2972
|
+
op: "contains",
|
|
2973
|
+
field: "title",
|
|
2974
|
+
value: "n_b"
|
|
2975
|
+
}],
|
|
2976
|
+
["in", {
|
|
2977
|
+
op: "in",
|
|
2978
|
+
field: "authorId",
|
|
2979
|
+
value: ["u1", "u2"]
|
|
2980
|
+
}],
|
|
2981
|
+
["notIn", {
|
|
2982
|
+
op: "notIn",
|
|
2983
|
+
field: "authorId",
|
|
2984
|
+
value: ["u1"]
|
|
2985
|
+
}],
|
|
2986
|
+
["isNull", {
|
|
2987
|
+
op: "isNull",
|
|
2988
|
+
field: "note",
|
|
2989
|
+
value: true
|
|
2990
|
+
}],
|
|
2991
|
+
["is not null", {
|
|
2992
|
+
op: "isNull",
|
|
2993
|
+
field: "note",
|
|
2994
|
+
value: false
|
|
2995
|
+
}],
|
|
2996
|
+
["and", {
|
|
2997
|
+
op: "and",
|
|
2998
|
+
conditions: [{
|
|
2999
|
+
op: "eq",
|
|
3000
|
+
field: "authorId",
|
|
3001
|
+
value: "u1"
|
|
3002
|
+
}, {
|
|
3003
|
+
op: "lt",
|
|
3004
|
+
field: "score",
|
|
3005
|
+
value: 10
|
|
3006
|
+
}]
|
|
3007
|
+
}],
|
|
3008
|
+
["or", {
|
|
3009
|
+
op: "or",
|
|
3010
|
+
conditions: [{
|
|
3011
|
+
op: "eq",
|
|
3012
|
+
field: "authorId",
|
|
3013
|
+
value: "u1"
|
|
3014
|
+
}, {
|
|
3015
|
+
op: "eq",
|
|
3016
|
+
field: "archived",
|
|
3017
|
+
value: true
|
|
3018
|
+
}]
|
|
3019
|
+
}],
|
|
3020
|
+
["not over a NULL field", {
|
|
3021
|
+
op: "not",
|
|
3022
|
+
condition: {
|
|
3023
|
+
op: "eq",
|
|
3024
|
+
field: "authorId",
|
|
3025
|
+
value: "u1"
|
|
3026
|
+
}
|
|
3027
|
+
}],
|
|
3028
|
+
["not over and", {
|
|
3029
|
+
op: "not",
|
|
3030
|
+
condition: {
|
|
3031
|
+
op: "and",
|
|
3032
|
+
conditions: [{
|
|
3033
|
+
op: "eq",
|
|
3034
|
+
field: "authorId",
|
|
3035
|
+
value: "u2"
|
|
3036
|
+
}, {
|
|
3037
|
+
op: "gt",
|
|
3038
|
+
field: "score",
|
|
3039
|
+
value: 5
|
|
3040
|
+
}]
|
|
3041
|
+
}
|
|
3042
|
+
}],
|
|
3043
|
+
["and of nothing", {
|
|
3044
|
+
op: "and",
|
|
3045
|
+
conditions: []
|
|
3046
|
+
}],
|
|
3047
|
+
["not of the empty allow set", {
|
|
3048
|
+
op: "not",
|
|
3049
|
+
condition: {
|
|
3050
|
+
op: "or",
|
|
3051
|
+
conditions: []
|
|
3052
|
+
}
|
|
3053
|
+
}]
|
|
3054
|
+
];
|
|
3055
|
+
const WHERE_SUBJECT = {
|
|
3056
|
+
principal: null,
|
|
3057
|
+
context: {}
|
|
3058
|
+
};
|
|
3059
|
+
/**
|
|
3060
|
+
* `matches` answers whether the compiled output selects `row`, for example
|
|
3061
|
+
* by running it against a table holding only that row. With it, every case
|
|
3062
|
+
* must select the rows the in-memory evaluator keeps, including rows whose
|
|
3063
|
+
* fields are NULL.
|
|
3064
|
+
*/
|
|
2632
3065
|
function testWhereCompiler(compiler, options) {
|
|
3066
|
+
const { matches } = options;
|
|
3067
|
+
it.skipIf(matches === void 0).each(WHERE_CASES)("selects the rows the evaluator keeps: %s", async (_name, condition) => {
|
|
3068
|
+
if (matches === void 0) return;
|
|
3069
|
+
const compiled = compiler(condition, options.target);
|
|
3070
|
+
const selected = [];
|
|
3071
|
+
for (const row of WHERE_ROWS) if (await matches(compiled, row)) selected.push(row["id"]);
|
|
3072
|
+
expect(selected).toEqual(WHERE_ROWS.filter((row) => evaluateCondition(condition, row, WHERE_SUBJECT)).map((row) => row["id"]));
|
|
3073
|
+
});
|
|
2633
3074
|
it("fails closed on an empty allow set", () => {
|
|
2634
3075
|
const compiled = compiler({
|
|
2635
3076
|
op: "or",
|
|
@@ -2815,7 +3256,7 @@ const supabaseClaimFixtures = {
|
|
|
2815
3256
|
}]
|
|
2816
3257
|
}
|
|
2817
3258
|
},
|
|
2818
|
-
|
|
3259
|
+
tenantPlans: {
|
|
2819
3260
|
claims: {
|
|
2820
3261
|
...base,
|
|
2821
3262
|
user_role: null,
|
|
@@ -2923,11 +3364,7 @@ const supabaseClaimFixtures = {
|
|
|
2923
3364
|
id: "5f0e4d3c-2b1a-4098-8776-655443322110",
|
|
2924
3365
|
kind: "oauth-client"
|
|
2925
3366
|
},
|
|
2926
|
-
delegation: { scopes: [
|
|
2927
|
-
"openid",
|
|
2928
|
-
"email",
|
|
2929
|
-
"posts:read"
|
|
2930
|
-
] }
|
|
3367
|
+
delegation: { scopes: ["posts:read"] }
|
|
2931
3368
|
}
|
|
2932
3369
|
},
|
|
2933
3370
|
actChain: {
|
|
@@ -3061,14 +3498,25 @@ const supabaseClaimFixtures = {
|
|
|
3061
3498
|
}
|
|
3062
3499
|
}
|
|
3063
3500
|
};
|
|
3501
|
+
const supabaseClaimVectors = {
|
|
3502
|
+
feature: "auth.session.get_claims",
|
|
3503
|
+
cases: Object.entries(supabaseClaimFixtures).map(([name, fixture]) => ({
|
|
3504
|
+
name,
|
|
3505
|
+
input: {
|
|
3506
|
+
claims: fixture.claims,
|
|
3507
|
+
...fixture.options === void 0 ? {} : { options: fixture.options }
|
|
3508
|
+
},
|
|
3509
|
+
expected: fixture.expect
|
|
3510
|
+
}))
|
|
3511
|
+
};
|
|
3064
3512
|
/**
|
|
3065
3513
|
* The `permdock supabase inspect --json` manifest for a policy with one
|
|
3066
3514
|
* `tenant` scope, the default `supabase.hook` and a `features` claim from
|
|
3067
|
-
* `
|
|
3515
|
+
* `public.feature_claims`. A package that reads the manifest tests its
|
|
3068
3516
|
* parser against this value.
|
|
3069
3517
|
*/
|
|
3070
3518
|
const supabaseHookManifestFixture = {
|
|
3071
|
-
$schema: "https://permdock.
|
|
3519
|
+
$schema: "https://permdock.com/schemas/supabase-manifest-v1.json",
|
|
3072
3520
|
version: 1,
|
|
3073
3521
|
hook: {
|
|
3074
3522
|
schema: "permdock",
|
|
@@ -3122,7 +3570,7 @@ const supabaseHookManifestFixture = {
|
|
|
3122
3570
|
},
|
|
3123
3571
|
{
|
|
3124
3572
|
name: "features",
|
|
3125
|
-
source: "
|
|
3573
|
+
source: "public.feature_claims",
|
|
3126
3574
|
budget: false
|
|
3127
3575
|
}
|
|
3128
3576
|
],
|
|
@@ -3177,6 +3625,12 @@ const supabaseHookManifestFixture = {
|
|
|
3177
3625
|
args: "p_user uuid",
|
|
3178
3626
|
returns: "setof uuid",
|
|
3179
3627
|
execute: ["supabase_auth_admin"]
|
|
3628
|
+
},
|
|
3629
|
+
{
|
|
3630
|
+
name: "permdock_user_id",
|
|
3631
|
+
args: "",
|
|
3632
|
+
returns: "uuid",
|
|
3633
|
+
execute: ["authenticated"]
|
|
3180
3634
|
}
|
|
3181
3635
|
],
|
|
3182
3636
|
memberships: [{
|
|
@@ -3191,7 +3645,13 @@ const supabaseHookManifestFixture = {
|
|
|
3191
3645
|
"scope_id",
|
|
3192
3646
|
"role"
|
|
3193
3647
|
]
|
|
3194
|
-
}]
|
|
3648
|
+
}],
|
|
3649
|
+
customRoles: false,
|
|
3650
|
+
roles: {
|
|
3651
|
+
table: "permdock.user_roles",
|
|
3652
|
+
user: { column: "user_id" },
|
|
3653
|
+
role: { column: "role" }
|
|
3654
|
+
}
|
|
3195
3655
|
},
|
|
3196
3656
|
decidingColumns: [
|
|
3197
3657
|
"public.memberships.role",
|
|
@@ -3202,7 +3662,11 @@ const supabaseHookManifestFixture = {
|
|
|
3202
3662
|
markers: {
|
|
3203
3663
|
hook: "v1",
|
|
3204
3664
|
grants: "v1"
|
|
3665
|
+
},
|
|
3666
|
+
requires: {
|
|
3667
|
+
matrix: "capability-matrix-v1.12.0",
|
|
3668
|
+
capabilities: ["auth.session.get_claims"]
|
|
3205
3669
|
}
|
|
3206
3670
|
};
|
|
3207
3671
|
//#endregion
|
|
3208
|
-
export { authzenTodoData, authzenTodoPermissions, authzenTodoPolicy, authzenTodoUsers, authzenTodoVectors, describePolicy, expectTypeOf, jwtFixtureAudience, jwtFixtureIssuer, jwtFixtureJwks, jwtFixtureTokens, ormParity, rlsParity, snapshotFixture, supabaseClaimFixtures, supabaseHookManifestFixture, supabaseMembershipsBudget, testApprovalPolicySource, testApprovalStore, testAuthZen, testClientParity, testClientStore, testCredentialVerifier, testDecisionSink, testDirectoryStore, testEntitlementSource, testHttpAdapter, testLimitStore, testMembershipSource, testPolicySource, testRelationSource, testReplayStore, testRevocationFeed, testRoleSource, testSettingsSource, testSnapshotSource, testSubjectResolver, testTokenSigner, testTokenVerifier, testWhereCompiler };
|
|
3672
|
+
export { AGENT_THROWING_ROW, AGENT_THROWING_USER, authzenTodoData, authzenTodoPermissions, authzenTodoPolicy, authzenTodoUsers, authzenTodoVectors, describePolicy, expectTypeOf, jwtFixtureAudience, jwtFixtureIssuer, jwtFixtureJwks, jwtFixtureTokens, ormParity, rlsParity, snapshotFixture, supabaseClaimFixtures, supabaseClaimVectors, supabaseHookManifestFixture, supabaseMembershipsBudget, testAgentAdapter, testApprovalPolicySource, testApprovalStore, testAuthZen, testClientParity, testClientStore, testCredentialVerifier, testDecisionSink, testDirectoryStore, testEntitlementSource, testHttpAdapter, testLimitStore, testMembershipSource, testPolicySource, testRelationSource, testReplayStore, testRevocationFeed, testRoleSource, testSettingsSource, testSnapshotSource, testSubjectResolver, testTokenSigner, testTokenVerifier, testWhereCompiler };
|