permdock 0.0.0 → 0.1.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 +268 -1
- package/dist/a2a/index.d.ts +178 -0
- package/dist/a2a/index.js +271 -0
- package/dist/ai-sdk/index.d.ts +74 -0
- package/dist/ai-sdk/index.js +137 -0
- package/dist/approval-required-TzNB9oQA.js +6 -0
- package/dist/approvals/index.d.ts +3 -0
- package/dist/approvals/index.js +4 -0
- package/dist/approvals-DaxY-Bdg.js +218 -0
- package/dist/approvers-aH0PJkmf.js +20 -0
- package/dist/arazzo-CTeVuXr5.js +70 -0
- package/dist/arazzo-aoTkqYsJ.js +54 -0
- package/dist/authzen/index.d.ts +48 -0
- package/dist/authzen/index.js +336 -0
- package/dist/better-auth/index.d.ts +92 -0
- package/dist/better-auth/index.js +324 -0
- package/dist/budget-JqcRqyhK.d.ts +11 -0
- package/dist/budget-NbEtbJC_.js +11 -0
- package/dist/capability-B68OFnZx.js +171 -0
- package/dist/capability-BDG_nkxt.d.ts +99 -0
- package/dist/catalog/index.d.ts +12 -0
- package/dist/catalog/index.js +2 -0
- package/dist/catalog-B0E6bggc.js +48 -0
- package/dist/catalog-H-vFGwWK.js +55 -0
- package/dist/catalog-doc-BSo_Q_-6.js +298 -0
- package/dist/catalog-idsHc0vo.js +2 -0
- package/dist/catalog-path-CnI0XTFK.js +12 -0
- package/dist/claude-agent/index.d.ts +81 -0
- package/dist/claude-agent/index.js +83 -0
- package/dist/clerk/index.d.ts +56 -0
- package/dist/clerk/index.js +280 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +20 -0
- package/dist/cli/index.d.ts +46 -0
- package/dist/cli/index.js +5 -0
- package/dist/cloud/index.d.ts +91 -0
- package/dist/cloud/index.js +390 -0
- package/dist/cloud-BNQTrmrr.js +50 -0
- package/dist/cloud-Cuxr6Czw.js +117 -0
- package/dist/collect-B7_TIfmg.js +49 -0
- package/dist/collect-O-tOtbnk.js +350 -0
- package/dist/collect-fRPAQIWb.js +2 -0
- package/dist/commands-BMh_Etm2.js +93 -0
- package/dist/compact-y6vfu2_f.js +19 -0
- package/dist/compare-pfyVnBjE.js +12 -0
- package/dist/compile-CQbvyIBr.d.ts +30 -0
- package/dist/compile-D22iwvuV.js +558 -0
- package/dist/config-BPYmjTOp.js +26 -0
- package/dist/connection-JvqwHODC.js +194 -0
- package/dist/context-CKEAabd7.js +73 -0
- package/dist/context-gtAwAILx.js +6 -0
- package/dist/convex/index.d.ts +40 -0
- package/dist/convex/index.js +55 -0
- package/dist/create-BKF3dgFk.d.ts +162 -0
- package/dist/create-CSkhDU9T.js +222 -0
- package/dist/credential-B_rkUNlY.js +326 -0
- package/dist/credentials-BgRX3WEg.js +268 -0
- package/dist/describe-Bt1YD5uS.js +99 -0
- package/dist/describe-DernyItf.d.ts +37 -0
- package/dist/diff-BUzf5Poi.js +48 -0
- package/dist/diff-x5Il8LVa.js +418 -0
- package/dist/digest-B3kc_PgQ.d.ts +19 -0
- package/dist/digest-BI-6aa6d.js +27 -0
- package/dist/doctor-BGle8Gqi.js +1314 -0
- package/dist/doctor-Bqo6FwUa.js +53 -0
- package/dist/drizzle/index.d.ts +72 -0
- package/dist/drizzle/index.js +160 -0
- package/dist/duration-xK2jGFVc.js +25 -0
- package/dist/elysia/index.d.ts +71 -0
- package/dist/elysia/index.js +103 -0
- package/dist/errors-DSMnAVNa.js +43 -0
- package/dist/errors-DbZ1YOnb.d.ts +138 -0
- package/dist/errors-Iy71s7Oj.js +177 -0
- package/dist/errors-m3u9TmDu.js +27 -0
- package/dist/evaluations-DsAU9ppl.js +479 -0
- package/dist/eve/index.d.ts +95 -0
- package/dist/eve/index.js +181 -0
- package/dist/express/index.d.ts +46 -0
- package/dist/express/index.js +108 -0
- package/dist/fastify/index.d.ts +56 -0
- package/dist/fastify/index.js +141 -0
- package/dist/files-B_wAGYmt.js +121 -0
- package/dist/fixtures-Cvaw0gDG.js +64 -0
- package/dist/freeze-y1_jQL4v.js +31 -0
- package/dist/from-snapshot-BMGnhmgv.js +552 -0
- package/dist/generate-CH7ThJ14.js +173 -0
- package/dist/grantee-Bv04_Vzf.js +521 -0
- package/dist/headers-B5RRv3Xm.js +6 -0
- package/dist/headers-C8SHQccD.d.ts +6 -0
- package/dist/helpers-DnSOrhB9.js +682 -0
- package/dist/hono/index.d.ts +70 -0
- package/dist/hono/index.js +131 -0
- package/dist/hosted-BwKQ1BTA.js +265 -0
- package/dist/http-DPuDaChb.d.ts +13 -0
- package/dist/http-GgVApX1k.js +111 -0
- package/dist/index-CltcQ4Bf.d.ts +138 -0
- package/dist/index-LF_hS-yn.d.ts +177 -0
- package/dist/index-fG6NSXlc.d.ts +9 -0
- package/dist/index-xIxJLwOQ.d.ts +415 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +21 -0
- package/dist/jwt/index.d.ts +87 -0
- package/dist/jwt/index.js +571 -0
- package/dist/kernel-YOGCWNLf.js +211 -0
- package/dist/kysely/index.d.ts +77 -0
- package/dist/kysely/index.js +129 -0
- package/dist/load-BZ24CpZP.js +69 -0
- package/dist/load-QOOm1z70.js +2 -0
- package/dist/load-jose-BL6LH4bL.js +11 -0
- package/dist/lru-8q4WZjBV.js +28 -0
- package/dist/manifest-DDQbC6K0.d.ts +118 -0
- package/dist/map-DowSO96j.js +158 -0
- package/dist/map-claims-B_6I1Rn-.js +360 -0
- package/dist/map-error-RJ3ZsUyA.js +16 -0
- package/dist/markers-B0hYLvMD.js +60 -0
- package/dist/may-use-CnFEjVEp.js +37 -0
- package/dist/mcp/index.d.ts +127 -0
- package/dist/mcp/index.js +563 -0
- package/dist/nest/index.d.ts +80 -0
- package/dist/nest/index.js +270 -0
- package/dist/next/client.d.ts +24 -0
- package/dist/next/client.js +31 -0
- package/dist/next/index.d.ts +110 -0
- package/dist/next/index.js +195 -0
- package/dist/next/plugin.d.ts +14 -0
- package/dist/next/plugin.js +2 -0
- package/dist/node/index.d.ts +43 -0
- package/dist/node/index.js +66 -0
- package/dist/openai/index.d.ts +71 -0
- package/dist/openai/index.js +105 -0
- package/dist/openapi/index.d.ts +93 -0
- package/dist/openapi/index.js +3 -0
- package/dist/openapi-CwePaF7C.js +164 -0
- package/dist/openapi-DWD0Uc_4.js +250 -0
- package/dist/openapi-DcqM8nU7.js +306 -0
- package/dist/openapi-import-BWRUNNeW.js +5959 -0
- package/dist/openapi-schema-D8j_T9tO.js +6902 -0
- package/dist/orpc/index.d.ts +64 -0
- package/dist/orpc/index.js +188 -0
- package/dist/otel/index.d.ts +13 -0
- package/dist/otel/index.js +202 -0
- package/dist/package-root-zGkxO3oN.js +30 -0
- package/dist/parse-DPfIvFMU.js +135 -0
- package/dist/pdp/index.d.ts +22 -0
- package/dist/pdp/index.js +795 -0
- package/dist/peer-BOr_kJE1.js +31 -0
- package/dist/permdock-yoZ7EjxX.js +2956 -0
- package/dist/permissions-B4apnahQ.d.ts +185 -0
- package/dist/permissions-B8vCg_bI.d.ts +52 -0
- package/dist/permissions-CofRqesP.js +142 -0
- package/dist/permissions-DC7GROPA.js +600 -0
- package/dist/pg-4GJWDUxG.js +953 -0
- package/dist/pins-CqE1jZuF.js +12 -0
- package/dist/plugin-4gr7IxFJ.js +65 -0
- package/dist/policy-ANp36PnI.js +971 -0
- package/dist/policy-CInmNGkM.d.ts +1959 -0
- package/dist/policy-Cq2fB8Q5.d.ts +20 -0
- package/dist/prisma/index.d.ts +135 -0
- package/dist/prisma/index.js +430 -0
- package/dist/problem-Cgp9-KZA.js +226 -0
- package/dist/prompt-CXYhLfsS.js +32 -0
- package/dist/protected-B4K3BKoX.js +138 -0
- package/dist/protected-BuPAycJT.d.ts +26 -0
- package/dist/protected-wY7nXhY9.d.ts +23 -0
- package/dist/provider-_wx46HpB.js +48 -0
- package/dist/provider-wTAUda2v.d.ts +6 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +6 -0
- package/dist/react/provider-client.d.ts +2 -0
- package/dist/react/provider-client.js +3 -0
- package/dist/react-native/index.d.ts +42 -0
- package/dist/react-native/index.js +174 -0
- package/dist/refs-ChLSxbST.js +90 -0
- package/dist/relations-r4soIFZB.js +426 -0
- package/dist/revocations-Cy06JNx2.d.ts +21 -0
- package/dist/rls-BOFU3chG.js +233 -0
- package/dist/rls-CJVja9Ww.js +2119 -0
- package/dist/rls-graph-DxQ39PJj.js +371 -0
- package/dist/rls-helpers-BxRuif0l.js +1346 -0
- package/dist/rls-import-CXV6LBlS.js +942 -0
- package/dist/rls-migrate-DrFPbf8p.js +366 -0
- package/dist/row-check-BajTgQZ-.d.ts +43 -0
- package/dist/run-CJ6UvS3a.js +155 -0
- package/dist/runtime-DP9ttFh1.js +27 -0
- package/dist/saas-BRrZzJkM.js +1193 -0
- package/dist/schema-P8yoma__.js +296 -0
- package/dist/scim/index.d.ts +2 -0
- package/dist/scim/index.js +2 -0
- package/dist/scim-9NFa0XVZ.js +1445 -0
- package/dist/scopes-cKVp_WTw.js +212 -0
- package/dist/server/index.d.ts +123 -0
- package/dist/server/index.js +8 -0
- package/dist/sha256-BO0swRXL.js +150 -0
- package/dist/sink-Bd9PSyfq.js +141 -0
- package/dist/sink-Cfr9-7YC.d.ts +104 -0
- package/dist/skills-C_lpV4Jx.js +50 -0
- package/dist/skills-Dx3QLnMY.js +110 -0
- package/dist/snapshot-DE8dE_hz.js +1051 -0
- package/dist/solid/index.d.ts +63 -0
- package/dist/solid/index.js +197 -0
- package/dist/source-DoBBYJi2.js +6 -0
- package/dist/sources-DOpW5Ila.d.ts +347 -0
- package/dist/sources-DVHM3Mwq.js +284 -0
- package/dist/sql-Bll1d7y0.js +22 -0
- package/dist/src-CTNT-PBW.js +430 -0
- package/dist/ssf/index.d.ts +3 -0
- package/dist/ssf/index.js +622 -0
- package/dist/store-Bq90395i.d.ts +27 -0
- package/dist/store-C6hFW6ta.js +508 -0
- package/dist/stores-CkG2HrSg.js +140 -0
- package/dist/stores-CvOnu_2T.d.ts +41 -0
- package/dist/stream-BhMfZOwr.d.ts +12 -0
- package/dist/stream-Q_xlB6Ko.js +52 -0
- package/dist/style-CTm1AXDT.js +22 -0
- package/dist/subject-C6dLxqHU.js +24 -0
- package/dist/subject-settings-xt7V845g.js +82 -0
- package/dist/supabase/index.d.ts +67 -0
- package/dist/supabase/index.js +4 -0
- package/dist/supabase/middleware.d.ts +77 -0
- package/dist/supabase/middleware.js +68 -0
- package/dist/supabase-D8UlBA7Z.js +83 -0
- package/dist/supabase-DTxGtYdi.js +796 -0
- package/dist/supabase-hook-DW-xP4hU.js +2 -0
- package/dist/supabase-hook-D_OqGb_V.js +1528 -0
- package/dist/svelte/Protected.svelte +34 -0
- package/dist/svelte/index.d.ts +10 -0
- package/dist/svelte/index.js +53 -0
- package/dist/svelte/runtime.d.ts +6 -0
- package/dist/svelte/runtime.js +3 -0
- package/dist/svelte/source.d.ts +10 -0
- package/dist/svelte/source.js +8 -0
- package/dist/terminal/index.d.ts +171 -0
- package/dist/terminal/index.js +821 -0
- package/dist/testing/index.d.ts +656 -0
- package/dist/testing/index.js +3208 -0
- package/dist/testing/saas/index.d.ts +194 -0
- package/dist/testing/saas/index.js +3 -0
- package/dist/testing/saas/permissions.d.ts +2 -0
- package/dist/testing/saas/permissions.js +2 -0
- package/dist/text-diff-BdkkYSbi.js +15 -0
- package/dist/thenable-okc2xDsj.js +10 -0
- package/dist/timeout-D51niuQP.js +8 -0
- package/dist/trpc/index.d.ts +80 -0
- package/dist/trpc/index.js +205 -0
- package/dist/types-B8w5PFtS.d.ts +141 -0
- package/dist/types-B9dmiiab.d.ts +66 -0
- package/dist/types-BBK-exvJ.d.ts +177 -0
- package/dist/types-BvBk1wgn.d.ts +118 -0
- package/dist/types-CxquUByI.d.ts +9 -0
- package/dist/types-D6Z6-rKJ.d.ts +312 -0
- package/dist/types-DbWdEfcm.d.ts +87 -0
- package/dist/types-bva3i4Gf.d.ts +98 -0
- package/dist/types-i4BAOvdb.d.ts +97 -0
- package/dist/unplugin/index.d.ts +7 -0
- package/dist/unplugin/index.js +30 -0
- package/dist/usage-1ozMubLY.js +42 -0
- package/dist/usage-CUnK6Ou9.js +530 -0
- package/dist/usage-PyEor6GA.js +2 -0
- package/dist/validity-D0uRmJKJ.js +224 -0
- package/dist/verifier-B90agnhl.js +461 -0
- package/dist/version-CnSh33Fj.js +16 -0
- package/dist/vocabulary-Dk0fs-Jk.d.ts +56 -0
- package/dist/vue/index.d.ts +57 -0
- package/dist/vue/index.js +203 -0
- package/dist/webmcp/index.d.ts +75 -0
- package/dist/webmcp/index.js +313 -0
- package/package.json +423 -4
- package/rulesets/permdock.yaml +29 -0
- package/schemas/catalog-v1.json +507 -0
- package/schemas/openapi/oas-3.1.json +1298 -0
- package/schemas/openapi/oas-3.2.json +1516 -0
- package/schemas/openapi/overlay-1.1.json +79 -0
- package/schemas/supabase-claims-v1.json +139 -0
- package/schemas/supabase-manifest-v1.json +217 -0
- package/skills/permdock/SKILL.md +66 -0
- package/skills/permdock-agents/SKILL.md +77 -0
- package/skills/permdock-agents/references/runtimes.md +211 -0
- package/skills/permdock-approvals/SKILL.md +80 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +83 -0
- package/skills/permdock-audit/SKILL.md +67 -0
- package/skills/permdock-credentials/SKILL.md +55 -0
- package/skills/permdock-credentials/references/tokens-keys-links.md +127 -0
- package/skills/permdock-data/SKILL.md +57 -0
- package/skills/permdock-data/references/queries-and-rls.md +54 -0
- package/skills/permdock-data/references/relationships.md +65 -0
- package/skills/permdock-tenancy/SKILL.md +77 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +83 -0
- package/skills/permdock-wire/SKILL.md +116 -0
- package/skills/permdock-wire/references/adapters.md +480 -0
- package/skills/permdock-wire/references/policy-options.md +43 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { o as rootMembershipId } from "./scopes-cKVp_WTw.js";
|
|
3
|
+
import { n as isApprovalError } from "./errors-m3u9TmDu.js";
|
|
4
|
+
import { f as assertApprover, m as approverRelations } from "./helpers-DnSOrhB9.js";
|
|
5
|
+
//#region src/approvals/handler.ts
|
|
6
|
+
const PROBLEM_BASE = "https://permdock.dev/problems";
|
|
7
|
+
function problem(status, title, detail, slug) {
|
|
8
|
+
const body = {
|
|
9
|
+
type: `${PROBLEM_BASE}/${slug}`,
|
|
10
|
+
title,
|
|
11
|
+
status,
|
|
12
|
+
detail
|
|
13
|
+
};
|
|
14
|
+
return new Response(JSON.stringify(body), {
|
|
15
|
+
status,
|
|
16
|
+
headers: { "content-type": "application/problem+json" }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function json(status, body) {
|
|
20
|
+
return new Response(JSON.stringify(body), {
|
|
21
|
+
status,
|
|
22
|
+
headers: { "content-type": "application/json" }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function parseRoute(url, method) {
|
|
26
|
+
const parts = url.pathname.replace(/\/+$/u, "").split("/").filter(Boolean);
|
|
27
|
+
const last = parts.at(-1);
|
|
28
|
+
const prev = parts.at(-2);
|
|
29
|
+
if (last === void 0) return;
|
|
30
|
+
if (method === "GET" && last === "pending") return { kind: "pending" };
|
|
31
|
+
if (method === "GET" && last === "mine") return { kind: "mine" };
|
|
32
|
+
if (method === "POST" && last === "approve" && prev !== void 0) return {
|
|
33
|
+
kind: "approve",
|
|
34
|
+
token: decodeURIComponent(prev)
|
|
35
|
+
};
|
|
36
|
+
if (method === "POST" && last === "reject" && prev !== void 0) return {
|
|
37
|
+
kind: "reject",
|
|
38
|
+
token: decodeURIComponent(prev)
|
|
39
|
+
};
|
|
40
|
+
if (method === "GET" && last !== "pending" && last !== "mine") return {
|
|
41
|
+
kind: "get",
|
|
42
|
+
token: decodeURIComponent(last)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function resolveSubject(request, resolve) {
|
|
46
|
+
try {
|
|
47
|
+
const subject = await resolve(request);
|
|
48
|
+
if (subject === null || subject === void 0) return null;
|
|
49
|
+
return subject;
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function membershipTenants(subject) {
|
|
55
|
+
const principal = subject.principal;
|
|
56
|
+
if (principal === null) return [];
|
|
57
|
+
const tenants = /* @__PURE__ */ new Set();
|
|
58
|
+
if (principal.tenant !== void 0) tenants.add(principal.tenant);
|
|
59
|
+
for (const membership of principal.memberships ?? []) {
|
|
60
|
+
const tenant = rootMembershipId(membership);
|
|
61
|
+
if (tenant !== void 0) tenants.add(tenant);
|
|
62
|
+
}
|
|
63
|
+
return [...tenants];
|
|
64
|
+
}
|
|
65
|
+
function belongsToTenant(subject, tenant) {
|
|
66
|
+
return membershipTenants(subject).includes(tenant);
|
|
67
|
+
}
|
|
68
|
+
async function mayResolve(request, subject, requireDistinct, options) {
|
|
69
|
+
try {
|
|
70
|
+
const relations = await approverRelations(request, subject, options);
|
|
71
|
+
assertApprover(request, subject, requireDistinct, /* @__PURE__ */ new Date(), relations);
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function canView(request, subject) {
|
|
78
|
+
const principal = subject.principal;
|
|
79
|
+
if (principal === null) return false;
|
|
80
|
+
if (request.subject.principal?.id === principal.id) return true;
|
|
81
|
+
const tenant = request.subject.principal?.tenant;
|
|
82
|
+
if (tenant !== void 0) return belongsToTenant(subject, tenant);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The tenants whose pending requests the approver may list: the requested one,
|
|
87
|
+
* else the active one, else every membership tenant. Requests without a tenant
|
|
88
|
+
* are listed only when no tenant was requested or active.
|
|
89
|
+
*/
|
|
90
|
+
function pageQuery(url) {
|
|
91
|
+
const limit = url.searchParams.get("limit");
|
|
92
|
+
const cursor = url.searchParams.get("cursor");
|
|
93
|
+
return compact({
|
|
94
|
+
limit: limit === null ? void 0 : Number(limit),
|
|
95
|
+
cursor: cursor ?? void 0
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function inboxScope(url, subject) {
|
|
99
|
+
const requested = url.searchParams.get("tenant");
|
|
100
|
+
if (requested !== null && requested !== "") {
|
|
101
|
+
if (!belongsToTenant(subject, requested)) return { ok: false };
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
tenants: [requested],
|
|
105
|
+
tenantless: false
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const active = subject.principal?.tenant;
|
|
109
|
+
if (active !== void 0) return {
|
|
110
|
+
ok: true,
|
|
111
|
+
tenants: [active],
|
|
112
|
+
tenantless: false
|
|
113
|
+
};
|
|
114
|
+
return {
|
|
115
|
+
ok: true,
|
|
116
|
+
tenants: membershipTenants(subject),
|
|
117
|
+
tenantless: true
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function signedApproval(request, signer, audience) {
|
|
121
|
+
if (signer === void 0 || request.status !== "approved") return Promise.resolve(void 0);
|
|
122
|
+
const payload = { approval: {
|
|
123
|
+
token: request.token,
|
|
124
|
+
permission: request.permission,
|
|
125
|
+
resource: request.resource,
|
|
126
|
+
status: request.status
|
|
127
|
+
} };
|
|
128
|
+
if (request.subject.principal !== null) payload["sub"] = request.subject.principal.id;
|
|
129
|
+
return signer.sign(payload, compact({
|
|
130
|
+
typ: "permdock-approval+jwt",
|
|
131
|
+
audience,
|
|
132
|
+
expiresAt: Math.floor(Date.parse(request.expiresAt) / 1e3)
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
async function readNote(request) {
|
|
136
|
+
const contentType = request.headers.get("content-type") ?? "";
|
|
137
|
+
if (request.method !== "POST" || contentType === "") return;
|
|
138
|
+
if (!contentType.includes("application/json")) return;
|
|
139
|
+
try {
|
|
140
|
+
const body = await request.json();
|
|
141
|
+
if (body !== null && typeof body === "object" && "note" in body && typeof body.note === "string") return body.note;
|
|
142
|
+
} catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function mapError(error) {
|
|
147
|
+
if (!isApprovalError(error)) return problem(500, "Internal error", "approval store failed", "internal");
|
|
148
|
+
if (error.code === "approval-not-found") return problem(404, "Not found", error.message, "not-found");
|
|
149
|
+
if (error.code === "approval-not-pending" || error.code === "approval-expired" || error.code === "approver-repeated") return problem(409, "Conflict", error.message, "conflict");
|
|
150
|
+
if (error.code === "approver-unauthenticated") return problem(401, "Unauthenticated", error.message, "unauthenticated");
|
|
151
|
+
return problem(403, "Permission denied", error.message, "denied");
|
|
152
|
+
}
|
|
153
|
+
function approvalsHandler(store, options) {
|
|
154
|
+
const requireDistinct = options.requireDistinctApprover === true;
|
|
155
|
+
return async (request) => {
|
|
156
|
+
const url = new URL(request.url);
|
|
157
|
+
const route = parseRoute(url, request.method);
|
|
158
|
+
if (route === void 0) return problem(405, "Method not allowed", "unknown approvals route", "method-not-allowed");
|
|
159
|
+
await store.expire();
|
|
160
|
+
const subject = await resolveSubject(request, options.subject);
|
|
161
|
+
const principal = subject?.principal ?? null;
|
|
162
|
+
if (subject === null || principal === null) return problem(401, "Unauthenticated", "approver must be authenticated", "unauthenticated");
|
|
163
|
+
try {
|
|
164
|
+
if (route.kind === "pending") {
|
|
165
|
+
const scoped = inboxScope(url, subject);
|
|
166
|
+
if (!scoped.ok) return problem(403, "Permission denied", "approver does not belong to that tenant", "denied");
|
|
167
|
+
const page = await store.list({
|
|
168
|
+
...pageQuery(url),
|
|
169
|
+
status: "pending"
|
|
170
|
+
});
|
|
171
|
+
const tenants = new Set(scoped.tenants);
|
|
172
|
+
const eligible = await Promise.all(page.items.map(async (item) => {
|
|
173
|
+
const tenant = item.subject.principal?.tenant;
|
|
174
|
+
return (tenant === void 0 ? scoped.tenantless : tenants.has(tenant)) && await mayResolve(item, subject, requireDistinct, options);
|
|
175
|
+
}));
|
|
176
|
+
return json(200, compact({
|
|
177
|
+
items: page.items.filter((_, index) => eligible[index] === true),
|
|
178
|
+
next: page.next
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
if (route.kind === "mine") {
|
|
182
|
+
const page = await store.list({
|
|
183
|
+
...pageQuery(url),
|
|
184
|
+
principalId: principal.id
|
|
185
|
+
});
|
|
186
|
+
return json(200, compact({
|
|
187
|
+
items: page.items,
|
|
188
|
+
next: page.next
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
if (route.kind === "get") {
|
|
192
|
+
const current = await store.get(route.token);
|
|
193
|
+
if (current === null || !canView(current, subject)) return problem(404, "Not found", "approval was not found", "not-found");
|
|
194
|
+
return json(200, current);
|
|
195
|
+
}
|
|
196
|
+
const current = await store.get(route.token);
|
|
197
|
+
if (current === null) return problem(404, "Not found", "approval was not found", "not-found");
|
|
198
|
+
const relations = await approverRelations(current, subject, options);
|
|
199
|
+
assertApprover(current, subject, requireDistinct, /* @__PURE__ */ new Date(), relations);
|
|
200
|
+
const note = await readNote(request);
|
|
201
|
+
const resolved = await store.resolve(route.token, compact({
|
|
202
|
+
status: route.kind === "approve" ? "approved" : "rejected",
|
|
203
|
+
by: subject,
|
|
204
|
+
note,
|
|
205
|
+
relations
|
|
206
|
+
}));
|
|
207
|
+
const signed = await signedApproval(resolved, options.signer, options.audience);
|
|
208
|
+
return json(200, compact({
|
|
209
|
+
...resolved,
|
|
210
|
+
signed
|
|
211
|
+
}));
|
|
212
|
+
} catch (error) {
|
|
213
|
+
return mapError(error);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
export { approvalsHandler as t };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { n as isReadonlyArray } from "./compact-y6vfu2_f.js";
|
|
2
|
+
//#region src/core/approvers.ts
|
|
3
|
+
/** A named approver for `approval.by`, matched on the approver's principal id. */
|
|
4
|
+
function user(id) {
|
|
5
|
+
if (typeof id !== "string" || id === "") throw new Error("PermDock: user() needs a non-empty principal id");
|
|
6
|
+
return Object.freeze({
|
|
7
|
+
kind: "user",
|
|
8
|
+
id
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function isUserApprover(value) {
|
|
12
|
+
return value !== null && typeof value === "object" && "kind" in value && value.kind === "user";
|
|
13
|
+
}
|
|
14
|
+
function flattenApprovers(input) {
|
|
15
|
+
if (input === void 0) return [];
|
|
16
|
+
if (isReadonlyArray(input)) return input;
|
|
17
|
+
return [input];
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { isUserApprover as n, user as r, flattenApprovers as t };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { p as arazzoFindings } from "./snapshot-DE8dE_hz.js";
|
|
2
|
+
import { a as loadModule, o as pickNamed, t as asPermissionTree } from "./load-BZ24CpZP.js";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
//#region src/cli/arazzo.ts
|
|
6
|
+
async function runArazzo(input) {
|
|
7
|
+
if (input.rest[0] !== "check") return {
|
|
8
|
+
code: 2,
|
|
9
|
+
output: "permdock arazzo check --doc <arazzo> --openapi <doc>"
|
|
10
|
+
};
|
|
11
|
+
const docPath = input.doc;
|
|
12
|
+
const openapiPath = input.openapi;
|
|
13
|
+
if (docPath === void 0 || openapiPath === void 0) return {
|
|
14
|
+
code: 2,
|
|
15
|
+
output: "arazzo check requires --doc and --openapi"
|
|
16
|
+
};
|
|
17
|
+
const arazzoFile = resolve(input.cwd, docPath);
|
|
18
|
+
const openapiFile = resolve(input.cwd, openapiPath);
|
|
19
|
+
if (!existsSync(arazzoFile) || !existsSync(openapiFile)) return {
|
|
20
|
+
code: 2,
|
|
21
|
+
output: "arazzo check: document not found"
|
|
22
|
+
};
|
|
23
|
+
let arazzo;
|
|
24
|
+
let openapi;
|
|
25
|
+
try {
|
|
26
|
+
arazzo = JSON.parse(readFileSync(arazzoFile, "utf8"));
|
|
27
|
+
openapi = JSON.parse(readFileSync(openapiFile, "utf8"));
|
|
28
|
+
} catch {
|
|
29
|
+
return {
|
|
30
|
+
code: 2,
|
|
31
|
+
output: "arazzo check: unreadable JSON"
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const from = input.from ?? input.config.permissions;
|
|
35
|
+
let tree;
|
|
36
|
+
if (from !== void 0) {
|
|
37
|
+
const abs = resolve(input.cwd, from);
|
|
38
|
+
if (!existsSync(abs)) return {
|
|
39
|
+
code: 2,
|
|
40
|
+
output: `arazzo check: permissions not found: ${from}`
|
|
41
|
+
};
|
|
42
|
+
const mod = await loadModule(abs);
|
|
43
|
+
tree = asPermissionTree(pickNamed(mod, ["permissions"]));
|
|
44
|
+
}
|
|
45
|
+
const findings = arazzoFindings(input.workflow === void 0 ? {
|
|
46
|
+
arazzo,
|
|
47
|
+
openapi
|
|
48
|
+
} : {
|
|
49
|
+
arazzo,
|
|
50
|
+
openapi,
|
|
51
|
+
workflowId: input.workflow
|
|
52
|
+
}, tree);
|
|
53
|
+
if (input.json) return {
|
|
54
|
+
code: findings.length === 0 ? 0 : 1,
|
|
55
|
+
output: JSON.stringify({
|
|
56
|
+
$schema: "permdock-arazzo-check",
|
|
57
|
+
findings
|
|
58
|
+
})
|
|
59
|
+
};
|
|
60
|
+
if (findings.length === 0) return {
|
|
61
|
+
code: 0,
|
|
62
|
+
output: "arazzo check: all steps documented"
|
|
63
|
+
};
|
|
64
|
+
return {
|
|
65
|
+
code: 1,
|
|
66
|
+
output: findings.map((finding) => `${finding.workflowId} ${finding.stepId}: ${finding.reason} (${finding.detail})`).join("\n")
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { runArazzo };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { a as listArg, i as globalArgs, s as stringArg, t as COMMAND_DESCRIPTIONS } from "./commands-BMh_Etm2.js";
|
|
2
|
+
import { defineCommand } from "citty";
|
|
3
|
+
//#region src/cli/commands/arazzo.ts
|
|
4
|
+
function arazzo(ctx) {
|
|
5
|
+
return defineCommand({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "arazzo",
|
|
8
|
+
description: COMMAND_DESCRIPTIONS.arazzo
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
...globalArgs,
|
|
12
|
+
action: {
|
|
13
|
+
type: "positional",
|
|
14
|
+
required: false,
|
|
15
|
+
description: "check"
|
|
16
|
+
},
|
|
17
|
+
doc: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Arazzo document",
|
|
20
|
+
valueHint: "arazzo.json"
|
|
21
|
+
},
|
|
22
|
+
openapi: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "OpenAPI document the workflows call",
|
|
25
|
+
valueHint: "doc.json"
|
|
26
|
+
},
|
|
27
|
+
workflow: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "Check one workflow",
|
|
30
|
+
valueHint: "id"
|
|
31
|
+
},
|
|
32
|
+
from: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Module exporting the policy, instead of the config",
|
|
35
|
+
valueHint: "module"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
async run({ args: parsed, rawArgs }) {
|
|
39
|
+
const result = await (await import("./arazzo-CTeVuXr5.js")).runArazzo({
|
|
40
|
+
cwd: ctx.cwd,
|
|
41
|
+
config: ctx.config,
|
|
42
|
+
rest: parsed._,
|
|
43
|
+
doc: listArg(rawArgs, "doc")[0],
|
|
44
|
+
openapi: stringArg(parsed.openapi),
|
|
45
|
+
workflow: stringArg(parsed.workflow),
|
|
46
|
+
from: stringArg(parsed.from),
|
|
47
|
+
json: ctx.json
|
|
48
|
+
});
|
|
49
|
+
ctx.report(result);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { arazzo };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { $ as DecisionSink, C as Policy, at as LimitStore, ct as MembershipSource, ft as RelationSource, mr as Principal, pt as RoleSource, sn as PolicySource, tt as EntitlementSource, xt as SnapshotSource } from "../policy-CInmNGkM.js";
|
|
2
|
+
import { f as ApprovalStore } from "../types-B8w5PFtS.js";
|
|
3
|
+
//#region src/authzen/types.d.ts
|
|
4
|
+
type AuthzenResourceAdapter = {
|
|
5
|
+
readonly load?: (id: string) => unknown;
|
|
6
|
+
readonly list?: (query: {
|
|
7
|
+
readonly where?: unknown;
|
|
8
|
+
}) => readonly unknown[] | Promise<readonly unknown[]>;
|
|
9
|
+
};
|
|
10
|
+
type AuthzenSubjectRecord = {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly [key: string]: unknown;
|
|
13
|
+
};
|
|
14
|
+
type AuthzenPermDockOptions<TUser = unknown> = {
|
|
15
|
+
readonly subject: (request: Request) => TUser | Promise<TUser>;
|
|
16
|
+
readonly anonymous?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Allow-list over the authenticated PEP. Only a PEP it returns `true` for
|
|
19
|
+
* may evaluate the body's `subject`, `actor` and `delegation`; every other
|
|
20
|
+
* caller is evaluated as itself. Off by default.
|
|
21
|
+
*/
|
|
22
|
+
readonly trustedPep?: (pep: unknown) => boolean;
|
|
23
|
+
readonly resources?: Readonly<Record<string, AuthzenResourceAdapter>>;
|
|
24
|
+
readonly subjects?: {
|
|
25
|
+
readonly list?: () => readonly AuthzenSubjectRecord[] | Promise<readonly AuthzenSubjectRecord[]>;
|
|
26
|
+
};
|
|
27
|
+
readonly memberships?: MembershipSource | readonly MembershipSource[];
|
|
28
|
+
/** The object graph for relation grants that walk a parent chain; without it they deny. */
|
|
29
|
+
readonly relations?: RelationSource;
|
|
30
|
+
readonly entitlements?: EntitlementSource;
|
|
31
|
+
readonly customRoles?: RoleSource;
|
|
32
|
+
/** Hosted grants, read once per instance; see `PolicySource`. */
|
|
33
|
+
readonly policies?: PolicySource;
|
|
34
|
+
readonly store?: ApprovalStore;
|
|
35
|
+
readonly sink?: DecisionSink;
|
|
36
|
+
readonly limits?: LimitStore;
|
|
37
|
+
readonly snapshots?: SnapshotSource;
|
|
38
|
+
readonly maxEvaluations?: number;
|
|
39
|
+
};
|
|
40
|
+
type AuthzenPermDock = {
|
|
41
|
+
readonly permdockHandler: (request: Request) => Promise<Response>;
|
|
42
|
+
};
|
|
43
|
+
type AuthzenFactory = <TUser, TPrincipal extends Principal = Principal>(policy: Policy<TUser, TPrincipal>, options: AuthzenPermDockOptions<TUser>) => AuthzenPermDock;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/authzen/create.d.ts
|
|
46
|
+
export declare const createPermDock: AuthzenFactory;
|
|
47
|
+
//#endregion
|
|
48
|
+
export type { AuthzenFactory, AuthzenPermDock, AuthzenPermDockOptions, AuthzenResourceAdapter, AuthzenSubjectRecord };
|