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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://permdock.
|
|
3
|
+
"$id": "https://permdock.com/schemas/supabase-claims-v1.json",
|
|
4
4
|
"title": "PermDock claims in a Supabase access token",
|
|
5
5
|
"description": "The claims the permdock supabase hook writes and the SQL helpers and subjectFromSupabase read, plus the OAuth claims subjectFromSupabase maps to the actor and delegation. Other claims pass through. Each hook claim may also sit under app_metadata. supabaseClaims() in permdock/supabase validates the same shape; tenant_id is the default rls.tenantClaim.",
|
|
6
6
|
"type": "object",
|
|
@@ -123,6 +123,11 @@
|
|
|
123
123
|
},
|
|
124
124
|
"managedBy": { "const": "idp" },
|
|
125
125
|
"entitlements": { "type": "array", "items": { "type": "string" } },
|
|
126
|
+
"keep": {
|
|
127
|
+
"description": "Set when the instance or an ancestor is suspended: the permission keys the membership still grants.",
|
|
128
|
+
"type": "array",
|
|
129
|
+
"items": { "type": "string", "minLength": 1 }
|
|
130
|
+
},
|
|
126
131
|
"grants": {
|
|
127
132
|
"description": "Custom roles in compact form, read by the helpers in jwt mode.",
|
|
128
133
|
"type": "object"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://permdock.
|
|
3
|
+
"$id": "https://permdock.com/schemas/supabase-manifest-v1.json",
|
|
4
4
|
"title": "PermDock Supabase hook manifest v1",
|
|
5
5
|
"description": "What `permdock supabase inspect --json` prints and `--out` writes: the generated hook, the SQL helpers, the claims, the membership sources and the columns that decide them. Fields are only added within v1.",
|
|
6
6
|
"type": "object",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"properties": {
|
|
22
22
|
"$schema": {
|
|
23
|
-
"const": "https://permdock.
|
|
23
|
+
"const": "https://permdock.com/schemas/supabase-manifest-v1.json"
|
|
24
24
|
},
|
|
25
25
|
"version": { "const": 1 },
|
|
26
26
|
"hook": {
|
|
@@ -29,7 +29,14 @@
|
|
|
29
29
|
"properties": {
|
|
30
30
|
"schema": { "$ref": "#/$defs/identifier" },
|
|
31
31
|
"function": { "const": "custom_access_token_hook" },
|
|
32
|
-
"out": { "type": "string" }
|
|
32
|
+
"out": { "type": "string" },
|
|
33
|
+
"before": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"items": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_]*\\.[A-Za-z_][A-Za-z0-9_]*$"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
33
40
|
}
|
|
34
41
|
},
|
|
35
42
|
"helpers": {
|
|
@@ -128,6 +135,69 @@
|
|
|
128
135
|
"memberships": {
|
|
129
136
|
"type": "array",
|
|
130
137
|
"items": { "$ref": "#/$defs/membership" }
|
|
138
|
+
},
|
|
139
|
+
"customRoles": { "type": "boolean" },
|
|
140
|
+
"roles": {
|
|
141
|
+
"type": "object",
|
|
142
|
+
"required": ["table", "user", "role"],
|
|
143
|
+
"additionalProperties": false,
|
|
144
|
+
"properties": {
|
|
145
|
+
"table": { "type": "string" },
|
|
146
|
+
"user": { "$ref": "#/$defs/column" },
|
|
147
|
+
"role": {
|
|
148
|
+
"oneOf": [
|
|
149
|
+
{ "$ref": "#/$defs/role" },
|
|
150
|
+
{
|
|
151
|
+
"type": "array",
|
|
152
|
+
"minItems": 2,
|
|
153
|
+
"items": { "$ref": "#/$defs/role" }
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"suspension": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"additionalProperties": false,
|
|
162
|
+
"properties": {
|
|
163
|
+
"users": { "$ref": "#/$defs/activeRow" },
|
|
164
|
+
"scopes": {
|
|
165
|
+
"type": "object",
|
|
166
|
+
"additionalProperties": { "$ref": "#/$defs/activeRow" }
|
|
167
|
+
},
|
|
168
|
+
"memberships": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"required": ["keep"],
|
|
171
|
+
"additionalProperties": false,
|
|
172
|
+
"properties": {
|
|
173
|
+
"keep": {
|
|
174
|
+
"description": "The permission keys a membership whose disabledAt column is set still holds.",
|
|
175
|
+
"type": "array",
|
|
176
|
+
"items": { "type": "string" }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"assignments": {
|
|
183
|
+
"type": "object",
|
|
184
|
+
"required": ["tables"],
|
|
185
|
+
"additionalProperties": false,
|
|
186
|
+
"properties": {
|
|
187
|
+
"tables": { "type": "array", "items": { "type": "string" } }
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"apiKeys": {
|
|
191
|
+
"type": "object",
|
|
192
|
+
"required": ["claim", "scopes", "tenant", "roles", "serviceRoles"],
|
|
193
|
+
"additionalProperties": false,
|
|
194
|
+
"properties": {
|
|
195
|
+
"claim": { "type": "string" },
|
|
196
|
+
"scopes": { "type": "string" },
|
|
197
|
+
"tenant": { "type": "string" },
|
|
198
|
+
"roles": { "type": "string" },
|
|
199
|
+
"serviceRoles": { "type": "array", "items": { "type": "string" } }
|
|
200
|
+
}
|
|
131
201
|
}
|
|
132
202
|
}
|
|
133
203
|
},
|
|
@@ -145,6 +215,26 @@
|
|
|
145
215
|
"hook": { "const": "v1" },
|
|
146
216
|
"grants": { "const": "v1" }
|
|
147
217
|
}
|
|
218
|
+
},
|
|
219
|
+
"requires": {
|
|
220
|
+
"description": "The supabase/sdk capability-matrix feature ids the hook, the helpers and subjectFromSupabase depend on, as of the matrix release tag.",
|
|
221
|
+
"type": "object",
|
|
222
|
+
"required": ["matrix", "capabilities"],
|
|
223
|
+
"additionalProperties": false,
|
|
224
|
+
"properties": {
|
|
225
|
+
"matrix": {
|
|
226
|
+
"type": "string",
|
|
227
|
+
"pattern": "^capability-matrix-v1\\.[0-9]+\\.[0-9]+$"
|
|
228
|
+
},
|
|
229
|
+
"capabilities": {
|
|
230
|
+
"type": "array",
|
|
231
|
+
"uniqueItems": true,
|
|
232
|
+
"items": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"pattern": "^[a-z][a-z0-9_]*\\.[a-z0-9_]+\\.[a-z0-9_]+$"
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
148
238
|
}
|
|
149
239
|
},
|
|
150
240
|
"$defs": {
|
|
@@ -156,10 +246,19 @@
|
|
|
156
246
|
"type": "string",
|
|
157
247
|
"pattern": "^[A-Za-z_][A-Za-z0-9_]*\\.[A-Za-z_][A-Za-z0-9_]*$"
|
|
158
248
|
},
|
|
159
|
-
"user": { "$ref": "#/$defs/
|
|
249
|
+
"user": { "$ref": "#/$defs/user" },
|
|
160
250
|
"scope": { "$ref": "#/$defs/value" },
|
|
161
251
|
"id": { "$ref": "#/$defs/column" },
|
|
162
|
-
"role": {
|
|
252
|
+
"role": {
|
|
253
|
+
"oneOf": [
|
|
254
|
+
{ "$ref": "#/$defs/role" },
|
|
255
|
+
{
|
|
256
|
+
"type": "array",
|
|
257
|
+
"minItems": 2,
|
|
258
|
+
"items": { "$ref": "#/$defs/role" }
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
},
|
|
163
262
|
"within": {
|
|
164
263
|
"oneOf": [
|
|
165
264
|
{ "$ref": "#/$defs/column" },
|
|
@@ -178,6 +277,7 @@
|
|
|
178
277
|
},
|
|
179
278
|
"via": { "$ref": "#/$defs/value" },
|
|
180
279
|
"expiresAt": { "$ref": "#/$defs/column" },
|
|
280
|
+
"disabledAt": { "$ref": "#/$defs/column" },
|
|
181
281
|
"columns": {
|
|
182
282
|
"type": "array",
|
|
183
283
|
"items": { "$ref": "#/$defs/identifier" }
|
|
@@ -185,9 +285,26 @@
|
|
|
185
285
|
}
|
|
186
286
|
},
|
|
187
287
|
"identifier": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
|
|
288
|
+
"activeRow": {
|
|
289
|
+
"type": "object",
|
|
290
|
+
"required": ["table", "id"],
|
|
291
|
+
"additionalProperties": false,
|
|
292
|
+
"properties": {
|
|
293
|
+
"table": { "type": "string" },
|
|
294
|
+
"id": { "$ref": "#/$defs/identifier" },
|
|
295
|
+
"disabledAt": { "$ref": "#/$defs/identifier" },
|
|
296
|
+
"status": { "$ref": "#/$defs/identifier" },
|
|
297
|
+
"active": { "type": "array", "items": { "type": "string" } },
|
|
298
|
+
"keep": {
|
|
299
|
+
"description": "A scope only: the permission keys members of a suspended instance still hold.",
|
|
300
|
+
"type": "array",
|
|
301
|
+
"items": { "type": "string" }
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
},
|
|
188
305
|
"helperName": {
|
|
189
306
|
"type": "string",
|
|
190
|
-
"pattern": "^(permdock_has
|
|
307
|
+
"pattern": "^(permdock_has(_for)?|permitted_[a-z][a-z0-9_]*_(ids|permission_keys)(_for)?|member_[a-z][a-z0-9_]*_ids(_for)?|permdock_can_assign(_any|_custom_role)?(_for)?|permdock_api_key_allows|permdock_user_id)$"
|
|
191
308
|
},
|
|
192
309
|
"column": {
|
|
193
310
|
"type": "object",
|
|
@@ -195,6 +312,33 @@
|
|
|
195
312
|
"additionalProperties": false,
|
|
196
313
|
"properties": { "column": { "$ref": "#/$defs/identifier" } }
|
|
197
314
|
},
|
|
315
|
+
"role": {
|
|
316
|
+
"oneOf": [{ "$ref": "#/$defs/value" }, { "$ref": "#/$defs/through" }]
|
|
317
|
+
},
|
|
318
|
+
"user": {
|
|
319
|
+
"oneOf": [{ "$ref": "#/$defs/column" }, { "$ref": "#/$defs/through" }]
|
|
320
|
+
},
|
|
321
|
+
"through": {
|
|
322
|
+
"type": "object",
|
|
323
|
+
"required": ["column", "through"],
|
|
324
|
+
"additionalProperties": false,
|
|
325
|
+
"properties": {
|
|
326
|
+
"column": { "$ref": "#/$defs/identifier" },
|
|
327
|
+
"through": {
|
|
328
|
+
"type": "object",
|
|
329
|
+
"required": ["table", "id", "column"],
|
|
330
|
+
"additionalProperties": false,
|
|
331
|
+
"properties": {
|
|
332
|
+
"table": {
|
|
333
|
+
"type": "string",
|
|
334
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_]*\\.[A-Za-z_][A-Za-z0-9_]*$"
|
|
335
|
+
},
|
|
336
|
+
"id": { "$ref": "#/$defs/identifier" },
|
|
337
|
+
"column": { "$ref": "#/$defs/identifier" }
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
},
|
|
198
342
|
"value": {
|
|
199
343
|
"oneOf": [
|
|
200
344
|
{ "$ref": "#/$defs/column" },
|
package/skills/permdock/SKILL.md
CHANGED
|
@@ -4,13 +4,13 @@ description: Explains how PermDock decides and routes to the right PermDock skil
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: ScaleDockHQ
|
|
7
|
-
homepage: https://permdock.
|
|
7
|
+
homepage: https://permdock.com/docs/for-ai-agents
|
|
8
8
|
repository: https://github.com/ScaleDockHQ/permdock
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# PermDock
|
|
12
12
|
|
|
13
|
-
PermDock is typed permissions for TypeScript apps, APIs, databases and AI agents. Permissions are defined once, decided in process, compiled to queries and RLS, and serialised to client snapshots ([for AI agents](https://permdock.
|
|
13
|
+
PermDock is typed permissions for TypeScript apps, APIs, databases and AI agents. Permissions are defined once, decided in process, compiled to queries and RLS, and serialised to client snapshots ([for AI agents](https://permdock.com/docs/for-ai-agents)). This skill holds the model every other PermDock skill assumes, and says which one to load.
|
|
14
14
|
|
|
15
15
|
## Inputs (find out before starting)
|
|
16
16
|
|
|
@@ -44,13 +44,13 @@ PermDock is typed permissions for TypeScript apps, APIs, databases and AI agents
|
|
|
44
44
|
|
|
45
45
|
✓ The skill for the task is loaded, and `permdock-wire` has run first if the app has no factory file.
|
|
46
46
|
|
|
47
|
-
2. **Look identifiers up, never guess them.** Read the owning page through the docs MCP (`https://permdock.
|
|
47
|
+
2. **Look identifiers up, never guess them.** Read the owning page through the docs MCP (`https://permdock.com/mcp`, tools `search`, `list_pages` and `get_page`), or append `.md` to any `https://permdock.com/docs/...` URL. Every public name follows the [naming convention](https://permdock.com/docs/getting-started/naming).
|
|
48
48
|
✓ Each identifier written into the app appears on a docs page or in `node_modules/permdock`.
|
|
49
|
-
3. **Read a decision.** `decide()` returns `{ outcome, denials: [{ reason, ... }], alternatives }`. `reason` is one of the closed list on [decisions](https://permdock.
|
|
49
|
+
3. **Read a decision.** `decide()` returns `{ outcome, denials: [{ reason, ... }], alternatives }`. `reason` is one of the closed list on [decisions](https://permdock.com/docs/concepts/decisions); `alternatives` are permissions on the same resource the subject does hold. HTTP adapters answer RFC 9457 Problem Details ([errors](https://permdock.com/docs/concepts/errors)); for the format, defer to the `problem-details` spec skill (`npx skills add ScaleDockHQ/scaledock-skills --skill problem-details`).
|
|
50
50
|
✓ Each denial the user asked about is named by its reason.
|
|
51
|
-
4. **Explain an unexpected denial.** Run `permdock.explain(permission, data)` in a test or a script. `trace.denies[0]` is the deny that won (give denies a `name` so it reads as a rule), `trace.allows` the allows it overrode, `trace.skipped` the grants passed over and why ([explain](https://permdock.
|
|
51
|
+
4. **Explain an unexpected denial.** Run `permdock.explain(permission, data)` in a test or a script. `trace.denies[0]` is the deny that won (give denies a `name` so it reads as a rule), `trace.allows` the allows it overrode, `trace.skipped` the grants passed over and why ([explain](https://permdock.com/docs/concepts/decisions#explain)). The trace never reaches the decision log. To preview a plan before acting, `simulate([[permission, data], ...])` returns every decision.
|
|
52
52
|
✓ The cause is a named grant, condition or missing input, not a guess.
|
|
53
|
-
5. **Check the project.** Run `pnpm exec permdock doctor` (`--json` for machine output). Each finding has a stable `PD0xx` code and a one-line fix ([doctor](https://permdock.
|
|
53
|
+
5. **Check the project.** Run `pnpm exec permdock doctor` (`--json` for machine output). Each finding has a stable `PD0xx` code and a one-line fix ([doctor](https://permdock.com/docs/cli/doctor)); the topic skills name the codes for their area.
|
|
54
54
|
✓ `permdock doctor` reports no error.
|
|
55
55
|
|
|
56
56
|
## Verify before done
|
|
@@ -63,4 +63,4 @@ PermDock is typed permissions for TypeScript apps, APIs, databases and AI agents
|
|
|
63
63
|
## Reference index
|
|
64
64
|
|
|
65
65
|
- Skills: `permdock-wire`, `permdock-audit`, `permdock-agents`, `permdock-approvals`, `permdock-tenancy`, `permdock-data`, `permdock-credentials`, all from `npx skills add ScaleDockHQ/PermDock --skill <name>`.
|
|
66
|
-
- Docs: [for AI agents](https://permdock.
|
|
66
|
+
- Docs: [for AI agents](https://permdock.com/docs/for-ai-agents), [naming](https://permdock.com/docs/getting-started/naming), [policies](https://permdock.com/docs/concepts/policies), [decisions](https://permdock.com/docs/concepts/decisions), [threat model](https://permdock.com/docs/security/threat-model), [doctor](https://permdock.com/docs/cli/doctor), `https://permdock.com/llms.txt`.
|
|
@@ -4,13 +4,13 @@ description: Guards AI agent tool calls with PermDock subjects, actors and deleg
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: ScaleDockHQ
|
|
7
|
-
homepage: https://permdock.
|
|
7
|
+
homepage: https://permdock.com/docs/security/delegation
|
|
8
8
|
repository: https://github.com/ScaleDockHQ/permdock
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# PermDock agents
|
|
12
12
|
|
|
13
|
-
An agent call has a principal (the user whose grants are evaluated), an actor (the agent making the call) and a delegation (what the user handed over). The decision is the principal's grants intersected with the delegation ([delegation](https://permdock.
|
|
13
|
+
An agent call has a principal (the user whose grants are evaluated), an actor (the agent making the call) and a delegation (what the user handed over). The decision is the principal's grants intersected with the delegation ([delegation](https://permdock.com/docs/security/delegation)). Set up `permissions.ts`, `policy.ts` and the factory first with the `permdock-wire` skill (`npx skills add ScaleDockHQ/PermDock --skill permdock-wire`).
|
|
14
14
|
|
|
15
15
|
## Inputs (find out, or ask before starting)
|
|
16
16
|
|
|
@@ -32,7 +32,7 @@ An agent call has a principal (the user whose grants are evaluated), an actor (t
|
|
|
32
32
|
|
|
33
33
|
## Workflow
|
|
34
34
|
|
|
35
|
-
1. **Name the three parts per surface.** Write down the principal source, the actor source and the delegation source for each runtime from the Inputs. The adapter table on [delegation](https://permdock.
|
|
35
|
+
1. **Name the three parts per surface.** Write down the principal source, the actor source and the delegation source for each runtime from the Inputs. The adapter table on [delegation](https://permdock.com/docs/security/delegation#how-adapters-fill-actor-and-delegation) shows what each adapter fills itself (MCP and A2A read token scopes; in-process runtimes take a `delegation` option).
|
|
36
36
|
✓ Every surface has all three, and none reads from model-controlled input.
|
|
37
37
|
2. **Map the tools.** Use the runtime's `createPermDock` with `subject`, `actor` and a `tools` map, and pass the returned hook to the runtime. -> [references/runtimes.md](references/runtimes.md)
|
|
38
38
|
✓ Every tool the agent can call has a `permission`, and every instance permission has a `data` loader that parses its arguments.
|
|
@@ -59,7 +59,7 @@ An agent call has a principal (the user whose grants are evaluated), an actor (t
|
|
|
59
59
|
✓ A destructive tool returns the runtime's approval outcome instead of running.
|
|
60
60
|
5. **Wire the agent-facing surfaces.** A2A: serve `agentCard()` publicly, `extendedAgentCard(auth)` behind auth, and `protectSkill` on the task endpoint. WebMCP: `registerTools` from a snapshot, with the server re-checking. Web Bot Auth: `webBotAuth: (request) => verifyWebBotAuth(request, { verify: true, keys })` on the HTTP adapter. -> [references/runtimes.md](references/runtimes.md)
|
|
61
61
|
✓ Each surface passes the Verify list of its spec skill.
|
|
62
|
-
6. **Test.** Add scenario tests with `permdock/testing` for one delegated grant, one `not-delegated` denial and one approval per destructive tool ([scenario testing](https://permdock.
|
|
62
|
+
6. **Test.** Add scenario tests with `permdock/testing` for one delegated grant, one `not-delegated` denial and one approval per destructive tool ([scenario testing](https://permdock.com/docs/guides/scenario-testing)). Then review with the `permdock-audit` skill, which reports ASI02 and ASI03 per adapter.
|
|
63
63
|
✓ The tests pass and the audit has no blocker.
|
|
64
64
|
|
|
65
65
|
## Verify before done
|
|
@@ -74,4 +74,4 @@ An agent call has a principal (the user whose grants are evaluated), an actor (t
|
|
|
74
74
|
## Reference index
|
|
75
75
|
|
|
76
76
|
- [references/runtimes.md](references/runtimes.md): factory shapes and outcome mapping for AI SDK, Claude Agent SDK, Eve, OpenAI Agents SDK, MCP, A2A, WebMCP, Web Bot Auth and `permdock/terminal`.
|
|
77
|
-
- Docs: [delegation](https://permdock.
|
|
77
|
+
- Docs: [delegation](https://permdock.com/docs/security/delegation), [subject](https://permdock.com/docs/concepts/subject), [OWASP Agentic mapping](https://permdock.com/docs/security/owasp-agentic), adapter pages under `https://permdock.com/docs/adapters/<name>`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent runtimes
|
|
2
2
|
|
|
3
|
-
Every agent adapter exports `createPermDock` from `permdock/<runtime>` and takes `subject`, `actor`, `delegation`, `tools` and `store`. One permission per tool. Instance actions load the row through `data`; tool input arrives as `unknown`, so parse it before loading. The current adapter page is `https://permdock.
|
|
3
|
+
Every agent adapter exports `createPermDock` from `permdock/<runtime>` and takes `subject`, `actor`, `delegation`, `tools` and `store`. One permission per tool. Instance actions load the row through `data`; tool input arrives as `unknown`, so parse it before loading. The current adapter page is `https://permdock.com/docs/adapters/<name>`.
|
|
4
4
|
|
|
5
5
|
## AI SDK — `permdock/ai-sdk`
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ export const { toolApproval, capabilityMiddleware, needsApproval } =
|
|
|
27
27
|
});
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Pass `toolApproval` into `generateText` / `ToolLoopAgent`. Wrap the model with `wrapLanguageModel({ model, middleware: capabilityMiddleware({ user }) })` per caller. Use `needsApproval(permissions.post.delete)` only on `WorkflowAgent`. `denied` maps to `'denied'`, `approval-required` to `'user-approval'`, and `'not-applicable'` is never returned ([AI SDK adapter](https://permdock.
|
|
30
|
+
Pass `toolApproval` into `generateText` / `ToolLoopAgent`. Wrap the model with `wrapLanguageModel({ model, middleware: capabilityMiddleware({ user }) })` per caller. Use `needsApproval(permissions.post.delete)` only on `WorkflowAgent`. `denied` maps to `'denied'`, `approval-required` to `'user-approval'`, and `'not-applicable'` is never returned ([AI SDK adapter](https://permdock.com/docs/adapters/ai-sdk)). Tools without a permission are hidden and denied unless `unmapped: 'allow'`; to combine PermDock with the app's own confirmation, pass `composeToolApproval(appApproval)` as `toolApproval` instead of wrapping the adapter: the app's function is asked only for calls PermDock grants, and its answer passes through (`undefined` stays not applicable; an unreadable answer denies).
|
|
31
31
|
|
|
32
32
|
## Claude Agent SDK — `permdock/claude-agent`
|
|
33
33
|
|
|
@@ -47,7 +47,7 @@ export const { canUseTool, permissionRequestHook } = createPermDock(policy, {
|
|
|
47
47
|
});
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
`canUseTool` returns `{ behavior: 'allow', updatedInput }` or `{ behavior: 'deny', message }`; approval-required is a deny whose message carries the pending token. Pass a `store`: once a reviewer approves, the retried call is allowed exactly once. `mcp__` tools are trusted only from `mcpSources` (default `['sdk']`). Pass `permissionRequestHook` under `hooks.PermissionRequest` ([Claude Agent adapter](https://permdock.
|
|
50
|
+
`canUseTool` returns `{ behavior: 'allow', updatedInput }` or `{ behavior: 'deny', message }`; approval-required is a deny whose message carries the pending token. Pass a `store`: once a reviewer approves, the retried call is allowed exactly once. `mcp__` tools are trusted only from `mcpSources` (default `['sdk']`). Pass `permissionRequestHook` under `hooks.PermissionRequest` ([Claude Agent adapter](https://permdock.com/docs/adapters/claude-agent)).
|
|
51
51
|
|
|
52
52
|
## Eve — `permdock/eve`
|
|
53
53
|
|
|
@@ -65,7 +65,7 @@ export const { approval, approvalFor, permdock } = createPermDock(policy, {
|
|
|
65
65
|
});
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
Pass `approval` as the tool's `approval`. Default subject and actor read `session.auth.initiator` / `current`. `approval.request(ctx)` maps granted to Eve's `not-applicable` (continue), approval-required to `user-approval`, denied to `{ type: 'denied', reason }`; Eve's re-check of a call nobody approved is denied. `approval.response(ctx)` maps the responder through the same `subject`. Use a durable `store` when replicas share sessions ([Eve adapter](https://permdock.
|
|
68
|
+
Pass `approval` as the tool's `approval`. Default subject and actor read `session.auth.initiator` / `current`. `approval.request(ctx)` maps granted to Eve's `not-applicable` (continue), approval-required to `user-approval`, denied to `{ type: 'denied', reason }`; Eve's re-check of a call nobody approved is denied. `approval.response(ctx)` maps the responder through the same `subject`. Use a durable `store` when replicas share sessions ([Eve adapter](https://permdock.com/docs/adapters/eve)).
|
|
69
69
|
|
|
70
70
|
## OpenAI Agents SDK — `permdock/openai`
|
|
71
71
|
|
|
@@ -86,7 +86,7 @@ export const { needsApproval, guardTools, resolveInterruptions, permdock } =
|
|
|
86
86
|
});
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
`needsApproval(permission)` is the tool's `needsApproval`; it reads `runContext.context` and is true unless granted. `guardTools` drops tools with no grant. `resolveInterruptions(state, interruptions, { context })` approves or rejects each pause and returns the still-pending `ApprovalRequest`s. On resume, rebuild the context from the session and use `RunState.fromStringWithContext` ([OpenAI adapter](https://permdock.
|
|
89
|
+
`needsApproval(permission)` is the tool's `needsApproval`; it reads `runContext.context` and is true unless granted. `guardTools` drops tools with no grant. `resolveInterruptions(state, interruptions, { context })` approves or rejects each pause and returns the still-pending `ApprovalRequest`s. On resume, rebuild the context from the session and use `RunState.fromStringWithContext` ([OpenAI adapter](https://permdock.com/docs/adapters/openai)).
|
|
90
90
|
|
|
91
91
|
## MCP — `permdock/mcp`
|
|
92
92
|
|
|
@@ -113,10 +113,12 @@ server.registerTool(
|
|
|
113
113
|
);
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
`actor.kind` is `'mcp-client'
|
|
116
|
+
`actor.kind` is `'mcp-client'` unless `actorKind` sets another (`'oauth-client'` makes the token the same actor kind `permdock/supabase` and `permdock/jwt` give it, so one delegation covers both), and `delegation` comes from the token's scopes and `authorization_details`. Every `registerTool` / `registerResource` / `registerPrompt` needs a `permission`. Lists are filtered per caller. A missing scope is an `insufficient_scope` step-up (HTTP `403`) naming only the scope the call needs. When the authorization server issues coarse scopes (`mcp:read`), declare them in `definePolicy({ oauthScopes })` instead of expanding scopes yourself: they are expanded into the delegation and named in challenges. Set `resource` to the server's URL so tokens for another audience are refused. Denied calls return `isError: true` with Decision `structuredContent`. `approval-required` parks the call in `store` and returns `isError: true` with the token, or an `input_required` URL request when `approval.at` is set and the client declares URL elicitation; the retried call runs once after approval (token optional under `_meta["dev.permdock/approval"]`, never from tool arguments) ([MCP adapter](https://permdock.com/docs/adapters/mcp)).
|
|
117
117
|
|
|
118
118
|
An MCP server that is not an SDK `McpServer` cannot be wrapped: narrow the tool's `meta` with `isPermission`, filter its tool list with `mayUse(permdock, permission)` from `permdock`, and decide each call with `permdock.decide(permission, args)` in its `authorize` hook. `mayUse` is a listing hint, never a decision.
|
|
119
119
|
|
|
120
|
+
When a tool's handler calls an oRPC procedure that runs `protect`, use `protectServer(server, { enforce: 'procedure', permissionFor: (name) => permissionOf(procedures.get(name)) })` with `permissionOf` from `permdock/orpc`. `tools/list` and annotations follow the permission; the call is not guarded, so each call decides once, in the procedure. `data` and `longRunning` throw in this mode, and the mode covers the whole server. When the same operations are REST routes, declare each permission once with `operationPermissions({ 'GET /customers/{id}': { permission, operationId } })` from `permdock/openapi` and pass `permissionFor: operations.forOperation`; the HTTP gate reads `operations.forRequest(method, path)` from the same object. When two operations share a permission but need different coarse scopes (reading an export with `mcp:read`, creating one with `mcp:write`), list the permission under both in `oauthScopes`, then narrow each operation with `oauthScopes: ['mcp:read']` on its entry (or on the tool config): pass `oauthScopesFor: operations.oauthScopesForOperation` to `protectServer`, and `operations` to `permdock/server` (or `protect`'s `oauthScopes`) for the REST routes, which then answer `insufficient_scope` naming that scope. A route that checks no permission but should still require a scope (a chat endpoint, setting the active organization) uses `protect(null, undefined, { oauthScopes: ['api:chat'] })` or an operation entry with only `oauthScopes`; never write an app-side rule that maps HTTP methods to scopes.
|
|
121
|
+
|
|
120
122
|
## A2A — `permdock/a2a`
|
|
121
123
|
|
|
122
124
|
```ts
|
|
@@ -151,7 +153,7 @@ app.post(
|
|
|
151
153
|
);
|
|
152
154
|
```
|
|
153
155
|
|
|
154
|
-
Identity comes from transport auth, never the task body. `actor.kind` is `'a2a'`, with `delegation` from the caller's token. Each skill's `securityRequirements` name the permission's `scope`. The public card is never filtered; `extendedAgentCard(auth)` keeps only skills the caller has a grant for. An instance-level skill without `data` throws at startup ([A2A adapter](https://permdock.
|
|
156
|
+
Identity comes from transport auth, never the task body. `actor.kind` is `'a2a'`, with `delegation` from the caller's token. Each skill's `securityRequirements` name the permission's `scope`. The public card is never filtered; `extendedAgentCard(auth)` keeps only skills the caller has a grant for. An instance-level skill without `data` throws at startup ([A2A adapter](https://permdock.com/docs/adapters/a2a)).
|
|
155
157
|
|
|
156
158
|
## WebMCP — `permdock/webmcp`
|
|
157
159
|
|
|
@@ -173,7 +175,7 @@ registerTools(document.modelContext, permissions.post, {
|
|
|
173
175
|
});
|
|
174
176
|
```
|
|
175
177
|
|
|
176
|
-
Never import a policy into this entry. A missing `document.modelContext` is a no-op. Tools re-register when the snapshot changes. The client check is a filter: the server adapter behind `api.posts` makes the decision. `onApprovalRequired` opens the page's own confirmation dialog ([WebMCP adapter](https://permdock.
|
|
178
|
+
Never import a policy into this entry. A missing `document.modelContext` is a no-op. Tools re-register when the snapshot changes. The client check is a filter: the server adapter behind `api.posts` makes the decision. `onApprovalRequired` opens the page's own confirmation dialog ([WebMCP adapter](https://permdock.com/docs/adapters/webmcp)).
|
|
177
179
|
|
|
178
180
|
## Web Bot Auth on HTTP adapters
|
|
179
181
|
|
|
@@ -192,7 +194,7 @@ export const { permdock, protect } = createPermDock(policy, {
|
|
|
192
194
|
});
|
|
193
195
|
```
|
|
194
196
|
|
|
195
|
-
A verified RFC 9421 signer becomes the actor with `kind: 'web-bot-auth'`; `delegation` comes from a bearer token on the same request, otherwise it is empty. A failed signature throws `InvalidSignatureError`, never an anonymous actor ([Web Bot Auth](https://permdock.
|
|
197
|
+
A verified RFC 9421 signer becomes the actor with `kind: 'web-bot-auth'`; `delegation` comes from a bearer token on the same request, otherwise it is empty. A failed signature throws `InvalidSignatureError`, never an anonymous actor ([Web Bot Auth](https://permdock.com/docs/standards/web-bot-auth)).
|
|
196
198
|
|
|
197
199
|
## Terminal — `permdock/terminal`
|
|
198
200
|
|
|
@@ -208,4 +210,4 @@ export const { permdock, protect, filterCommands, format, exitCode } =
|
|
|
208
210
|
});
|
|
209
211
|
```
|
|
210
212
|
|
|
211
|
-
For the app's own CLI; not the `permdock` binary. Never accept `--user` or `--actor` as identity. In CI, verify the job token with `subjectFromCiOidc(jwt, { provider: 'github', audience })` from `permdock/jwt`, which returns a `workload` principal, never a user. A `destructive` permission asks for the resource id to be typed, and exits `64` without a terminal unless `--yes` is passed; `--yes` never approves an `approval-required` call. `--dry-run` decides and exits with the outcome's code without running the action ([terminal adapter](https://permdock.
|
|
213
|
+
For the app's own CLI; not the `permdock` binary. Never accept `--user` or `--actor` as identity. In CI, verify the job token with `subjectFromCiOidc(jwt, { provider: 'github', audience })` from `permdock/jwt`, which returns a `workload` principal, never a user. A `destructive` permission asks for the resource id to be typed, and exits `64` without a terminal unless `--yes` is passed; `--yes` never approves an `approval-required` call. `--dry-run` decides and exits with the outcome's code without running the action ([terminal adapter](https://permdock.com/docs/adapters/terminal)).
|
|
@@ -4,13 +4,13 @@ description: Requires human approval on PermDock grants and resumes the approved
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: ScaleDockHQ
|
|
7
|
-
homepage: https://permdock.
|
|
7
|
+
homepage: https://permdock.com/docs/security/approvals
|
|
8
8
|
repository: https://github.com/ScaleDockHQ/permdock
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# PermDock approvals
|
|
12
12
|
|
|
13
|
-
`approval-required` is the third outcome: the subject may do it, but a person other than the requester confirms each call. An approval never grants something the subject could not do, and a `deny` still wins ([approval security](https://permdock.
|
|
13
|
+
`approval-required` is the third outcome: the subject may do it, but a person other than the requester confirms each call. An approval never grants something the subject could not do, and a `deny` still wins ([approval security](https://permdock.com/docs/security/approvals)). Set up the policy and factory first with the `permdock-wire` skill (`npx skills add ScaleDockHQ/PermDock --skill permdock-wire`).
|
|
14
14
|
|
|
15
15
|
## Inputs (find out, or ask before starting)
|
|
16
16
|
|
|
@@ -61,7 +61,7 @@ metadata:
|
|
|
61
61
|
✓ `testApprovalPolicySource` from `permdock/testing` passes on the source.
|
|
62
62
|
6. **Surface and resume.** Map the outcome to each runtime's approval hook and resume with the token: the `PermDock-Approval` header over HTTP, the runtime's own resume for agents. -> [references/stores-and-resume.md](references/stores-and-resume.md#surfaces)
|
|
63
63
|
✓ The approved call runs once; a second resume is denied with `approval-consumed`.
|
|
64
|
-
7. **Test.** Add a scenario test per approval grant: the ask, an approval by an eligible user, a refused self-approval, and the single resume ([scenario testing](https://permdock.
|
|
64
|
+
7. **Test.** Add a scenario test per approval grant: the ask, an approval by an eligible user, a refused self-approval, and the single resume ([scenario testing](https://permdock.com/docs/guides/scenario-testing)). Run `testApprovalStore` on a custom store.
|
|
65
65
|
✓ The tests pass.
|
|
66
66
|
|
|
67
67
|
## Verify before done
|
|
@@ -77,4 +77,4 @@ metadata:
|
|
|
77
77
|
## Reference index
|
|
78
78
|
|
|
79
79
|
- [references/stores-and-resume.md](references/stores-and-resume.md): `approvalsHandler` routes, custom stores, relation approvers, approval policies as data, the token, resume details and denial causes, the runtime surfaces table, delivery to chat and email.
|
|
80
|
-
- Docs: [approval security](https://permdock.
|
|
80
|
+
- Docs: [approval security](https://permdock.com/docs/security/approvals), [approvals adapter](https://permdock.com/docs/adapters/approvals), [wire formats](https://permdock.com/docs/concepts/wire-formats).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Approval stores and the resume flow
|
|
2
2
|
|
|
3
|
-
The API and the store contract are on the [approvals adapter](https://permdock.
|
|
3
|
+
The API and the store contract are on the [approvals adapter](https://permdock.com/docs/adapters/approvals); the token and the runtime table are on [approval security](https://permdock.com/docs/security/approvals).
|
|
4
4
|
|
|
5
5
|
## Store and handler
|
|
6
6
|
|
|
@@ -22,8 +22,11 @@ const handler = approvalsHandler(store, {
|
|
|
22
22
|
app.all("/permdock/approvals/*", (c) => handler(c.req.raw));
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The store's `ttl` is the window a request stays open when the call sets none; `resumeDecision({ ..., ttl })` sets it per call (milliseconds). A grant's `approval.ttl` only shortens either.
|
|
26
|
+
|
|
27
|
+
- `memoryApprovalStore` is per process. On serverless or with several replicas, implement `ApprovalStore` over the app's database; the Drizzle recipe on the adapter page is the template, and `cloud().approvals` from `permdock/cloud` is the hosted implementation of the same interface. On Postgres or Supabase, set `rls.approvals: true` and use `supabaseApprovalStore(admin, { onOpen })` from `permdock/supabase` over the generated table and functions; grant the functions to the server's role, and put notifications and superseding older requests in `onOpen`.
|
|
26
28
|
- A custom store calls `assertApprover(request, by, requireDistinct, now, verdict.relations)` in `resolve` and computes the next record with `applyApprovalVerdict`, which records each signature's `stage`. `verdict.relations` holds `approverRelationKey` values that the handler, or `resolveApproval(store, token, verdict, { relations, permissions })`, computed with `approverRelations`; a store never derives them. `consume` must be atomic: two concurrent calls never both succeed.
|
|
29
|
+
- When the app's own rules decide who approves (a manager chain, delegates, a quorum it counts), record their verdict with `vouchApproval(store, token, { status, by, rule })` from `permdock/approvals` instead of mirroring those rules in `approvers` or copying the verdict into the request by hand. It resolves the request at once and records `vouched: rule`; the actor, requester and repeat checks still apply. Never take `vouched` from a request body.
|
|
27
30
|
- Run `testApprovalStore(store, { reopen })` from `permdock/testing` on every custom store.
|
|
28
31
|
- `cancelApprovals` rejects matching pending requests (for example when a session ends).
|
|
29
32
|
|
|
@@ -39,14 +42,16 @@ const permdock = await createPermDock(policy, user, {
|
|
|
39
42
|
tenant: "o_acme", // absent: every tenant
|
|
40
43
|
actors: ["agent"], // absent: every call
|
|
41
44
|
where: { op: "gt", field: "amount", value: 1000 },
|
|
42
|
-
approval: { by: "finance" }, //
|
|
45
|
+
approval: { by: "finance" }, // an escalation here widens only this entry's stages
|
|
43
46
|
},
|
|
44
47
|
]),
|
|
45
48
|
});
|
|
46
49
|
```
|
|
47
50
|
|
|
51
|
+
- Every adapter's `createPermDock` takes `approvalPolicies` (HTTP, MCP, A2A, AuthZEN, terminal and the agent adapters), so an entry also turns an agent call into `user-approval` or an MCP call into `approval-required`.
|
|
48
52
|
- Entries are read once per instance and combine with the grant's own approval as stages (`sequential` if any part is, else `all`); the shortest `ttl` wins.
|
|
49
53
|
- A throw or an invalid entry denies with detail `approval-policy-unavailable`. An unknown permission applies to nothing.
|
|
54
|
+
- `where` reads the row, so it works only on instance permissions; on a collection permission the entry does not load. Use `check` (the proposed row) there. Validate entries where they are saved with `validateApprovalPolicy(policy, entry)` (`{ ok: false, problem }` names `unknown-permission`, `invalid`, `where-on-collection` or `stale-on-without-version`).
|
|
50
55
|
- Client snapshots do not see the entries; the server's `decide` adds the approval.
|
|
51
56
|
|
|
52
57
|
## Resume
|
|
@@ -57,6 +62,8 @@ const permdock = await createPermDock(policy, user, {
|
|
|
57
62
|
|
|
58
63
|
The token binds the permission key, the resource id (or a digest of the data when there is no id), the principal, the tenant, the actor and the matched grant's conditions. Under `staleOn: 'resource-change'` it also binds the row's `version`.
|
|
59
64
|
|
|
65
|
+
A gate in your own code resumes the same way with `resumeDecision` from `permdock/approvals`, passing `token: carried ?? (await storedApprovalToken(store, decision))`: `storedApprovalToken` finds an approved or rejected request for the recomputed token, so the caller need not carry it. Do not reimplement it.
|
|
66
|
+
|
|
60
67
|
Over HTTP, the client retries the same request with the `PermDock-Approval: <token>` header. In React, `approvalHeaders(token)` builds that header and `useApproval(decision)` requests and polls an approval from the UI.
|
|
61
68
|
|
|
62
69
|
A bad resume is denied with detail `approval-not-found`, `approval-pending`, `approval-rejected`, `approval-expired`, `approval-consumed` or `approval-mismatch`; a changed row is `stale-approval`. `approvalsHandler` answers `403` for an ineligible approver (`approver-not-eligible`, the actor, or the principal without `distinct: false`) and `409` for a repeated one (`approver-repeated`).
|
|
@@ -80,4 +87,8 @@ For AG-UI event shapes, defer to the `ag-ui` spec skill (`npx skills add ScaleDo
|
|
|
80
87
|
|
|
81
88
|
## Delivery
|
|
82
89
|
|
|
83
|
-
Notifying an approver is a listener on the `approval` event (`permdock.on('approval', …)`), never a package. A message or email carries only the token and links to a page where the approver signs in; the verdict goes through `approvalsHandler` with that session's subject. A link never approves on its own ([approvals adapter, Delivery](https://permdock.
|
|
90
|
+
Notifying an approver is a listener on the `approval` event (`permdock.on('approval', …)`), never a package. A message or email carries only the token and links to a page where the approver signs in; the verdict goes through `approvalsHandler` with that session's subject. A link never approves on its own ([approvals adapter, Delivery](https://permdock.com/docs/adapters/approvals#delivery)).
|
|
91
|
+
|
|
92
|
+
## Approvers
|
|
93
|
+
|
|
94
|
+
`by` takes roles, `user(id)`, `relation()`, `holder(permission)` and `anyOf(...)`. A list is all-of; use `anyOf(user(id), holder(permissions.x.approve))` for "this person or anyone who holds the permission". `holder()` needs `approvalsHandler(store, { permdockFor: (approver, request) => createPermDock(policy, approver, { customRoles }) })`, so custom roles count. Stages may carry their own `escalation`.
|
|
@@ -4,7 +4,7 @@ description: Reviews an existing PermDock setup or a pull request that changes i
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: ScaleDockHQ
|
|
7
|
-
homepage: https://permdock.
|
|
7
|
+
homepage: https://permdock.com/docs/for-ai-agents
|
|
8
8
|
repository: https://github.com/ScaleDockHQ/permdock
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -42,7 +42,7 @@ Read the app's `permissions.ts`, `policy.ts`, factory file and every adapter gua
|
|
|
42
42
|
✓ Every item of every applicable Verify list has a pass or a finding.
|
|
43
43
|
5. **Tests.** No `describePolicy` suite, or one with `exhaustive: false`, is a finding: a new permission can ship untested. A custom `ApprovalStore`, `DecisionSink`, `MembershipSource`, `RoleSource`, `SnapshotSource`, `LimitStore`, `RelationSource` or `DirectoryStore` without its `test<Interface>` runner from `permdock/testing` is a finding.
|
|
44
44
|
✓ Every policy and custom store has its runner, or a finding.
|
|
45
|
-
6. **ASI02 and ASI03.** Map the inventory onto [OWASP Agentic](https://permdock.
|
|
45
|
+
6. **ASI02 and ASI03.** Map the inventory onto [OWASP Agentic](https://permdock.com/docs/security/owasp-agentic); for the threat list itself, defer to the `owasp-agentic` spec skill (`npx skills add ScaleDockHQ/scaledock-skills --skill owasp-agentic`).
|
|
46
46
|
- **ASI02** (tool misuse): unmapped tools, a collection permission on a row handler, a destructive tool without `approval`, capability lists that include denied tools.
|
|
47
47
|
- **ASI03** (identity and privilege abuse): a model-supplied subject or actor, an actor used as approver, `distinct: false` on a sensitive action, a resume token not bound to permission, resource, subject and actor, API keys stored in plain text or created outside `decideCredential`, keys without expiry (PD029), and a `memberships` source applied to service-key subjects.
|
|
48
48
|
✓ Each agent adapter in the app has an ASI02 line and an ASI03 line.
|
|
@@ -64,4 +64,4 @@ Read the app's `permissions.ts`, `policy.ts`, factory file and every adapter gua
|
|
|
64
64
|
## Reference index
|
|
65
65
|
|
|
66
66
|
- Topic Verify lists: the `permdock-agents`, `permdock-approvals`, `permdock-tenancy`, `permdock-data` and `permdock-credentials` skills.
|
|
67
|
-
- Docs: [OWASP Agentic mapping](https://permdock.
|
|
67
|
+
- Docs: [OWASP Agentic mapping](https://permdock.com/docs/security/owasp-agentic), [threat model](https://permdock.com/docs/security/threat-model), [`permdock doctor`](https://permdock.com/docs/cli/doctor), [`permdock usage`](https://permdock.com/docs/cli/usage), [testing](https://permdock.com/docs/adapters/testing).
|
|
@@ -4,13 +4,13 @@ description: Resolves PermDock subjects from access tokens, API keys and share l
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: ScaleDockHQ
|
|
7
|
-
homepage: https://permdock.
|
|
7
|
+
homepage: https://permdock.com/docs/concepts/authentication
|
|
8
8
|
repository: https://github.com/ScaleDockHQ/permdock
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# PermDock credentials
|
|
12
12
|
|
|
13
|
-
Authentication is upstream: core never verifies a token. A `subjectFrom*` resolver verifies the material and hands core a `Subject`, and anything it cannot verify becomes the anonymous subject, never a throw ([authentication](https://permdock.
|
|
13
|
+
Authentication is upstream: core never verifies a token. A `subjectFrom*` resolver verifies the material and hands core a `Subject`, and anything it cannot verify becomes the anonymous subject, never a throw ([authentication](https://permdock.com/docs/concepts/authentication)). Set up the policy and factory first with the `permdock-wire` skill (`npx skills add ScaleDockHQ/PermDock --skill permdock-wire`).
|
|
14
14
|
|
|
15
15
|
## Inputs (find out, or ask before starting)
|
|
16
16
|
|
|
@@ -38,7 +38,7 @@ Authentication is upstream: core never verifies a token. A `subjectFrom*` resolv
|
|
|
38
38
|
✓ A revoked or expired key is anonymous, and a user key never exceeds its owner's current rights.
|
|
39
39
|
4. **Share links, when the product has them.** Declare the link's roles on the resource, mint with `signCapability` behind a guard of its own, and resolve with `subjectFromCapability` and the tenant's `linkPolicy`. With Supabase RLS, exchange the link with `exchangeCapability` and generate with `--capabilities`. -> [references/tokens-keys-links.md](references/tokens-keys-links.md#share-links)
|
|
40
40
|
✓ An expired, revoked or replayed (`once`) link resolves to the anonymous subject.
|
|
41
|
-
5. **Test.** Add scenario tests for each credential kind: a valid one, a forged or expired one, and a key or link used past its permissions ([scenario testing](https://permdock.
|
|
41
|
+
5. **Test.** Add scenario tests for each credential kind: a valid one, a forged or expired one, and a key or link used past its permissions ([scenario testing](https://permdock.com/docs/guides/scenario-testing)). Run `permdock doctor`.
|
|
42
42
|
✓ The tests pass and PD029 is clean.
|
|
43
43
|
|
|
44
44
|
## Verify before done
|
|
@@ -52,4 +52,4 @@ Authentication is upstream: core never verifies a token. A `subjectFrom*` resolv
|
|
|
52
52
|
## Reference index
|
|
53
53
|
|
|
54
54
|
- [references/tokens-keys-links.md](references/tokens-keys-links.md): `subjectFromJwt` options, introspection, CI OIDC, `decideCredential`, key storage and resolution, tenant settings, `signCapability`, `subjectFromCapability`, `exchangeCapability`.
|
|
55
|
-
- Docs: [authentication](https://permdock.
|
|
55
|
+
- Docs: [authentication](https://permdock.com/docs/concepts/authentication), [subject](https://permdock.com/docs/concepts/subject), [JWT adapter](https://permdock.com/docs/adapters/jwt), [API keys](https://permdock.com/docs/concepts/credentials), [link capabilities](https://permdock.com/docs/concepts/capabilities), [JOSE](https://permdock.com/docs/standards/jose).
|