@executioncontrolprotocol/policies 0.10.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/dist/image-policy-eval.d.ts +21 -0
- package/dist/image-policy-eval.d.ts.map +1 -0
- package/dist/image-policy-eval.js +83 -0
- package/dist/image-policy-eval.js.map +1 -0
- package/dist/image-policy.d.ts +7 -0
- package/dist/image-policy.d.ts.map +1 -0
- package/dist/image-policy.js +54 -0
- package/dist/image-policy.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +157 -0
- package/dist/index.js.map +1 -0
- package/dist/registry-control.d.ts +18 -0
- package/dist/registry-control.d.ts.map +1 -0
- package/dist/registry-control.js +69 -0
- package/dist/registry-control.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Image policy configuration shape. @category Policies */
|
|
2
|
+
export interface ImagePolicyConfig {
|
|
3
|
+
allowedInputKinds?: Array<"artifact" | "file" | "url" | "buffer">;
|
|
4
|
+
allowedOutputFormats?: Array<"jpeg" | "png" | "webp" | "avif" | "tiff" | "gif" | "raw">;
|
|
5
|
+
maxImageRefsPerStep?: number;
|
|
6
|
+
maxInputBytes?: number;
|
|
7
|
+
maxOutputBytes?: number;
|
|
8
|
+
maxPixels?: number;
|
|
9
|
+
maxWidth?: number;
|
|
10
|
+
maxHeight?: number;
|
|
11
|
+
allowSvg?: boolean;
|
|
12
|
+
allowRemoteUrls?: boolean;
|
|
13
|
+
allowedUrlDomains?: string[];
|
|
14
|
+
requireStripMetadata?: boolean;
|
|
15
|
+
denyRawOutput?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Evaluate image refs in step input against policy config. @category Policies */
|
|
18
|
+
export declare function evaluateImageRefsPre(input: Record<string, unknown>, config: ImagePolicyConfig): string | undefined;
|
|
19
|
+
/** Evaluate image output against policy config. @category Policies */
|
|
20
|
+
export declare function evaluateImageRefsPost(output: unknown, config: ImagePolicyConfig): string | undefined;
|
|
21
|
+
//# sourceMappingURL=image-policy-eval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-policy-eval.d.ts","sourceRoot":"","sources":["../src/image-policy-eval.ts"],"names":[],"mappings":"AAQA,2DAA2D;AAC3D,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAA;IACjE,oBAAoB,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC,CAAA;IACvF,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,kFAAkF;AAClF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,iBAAiB,GACxB,MAAM,GAAG,SAAS,CAqCpB;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,iBAAiB,GACxB,MAAM,GAAG,SAAS,CAiDpB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { collectImageRefs, collectOutputFormatHints, imageRefUrlHostname, isSvgHint, } from "@executioncontrolprotocol/core";
|
|
2
|
+
import { IMAGE_REF_KINDS } from "@executioncontrolprotocol/types";
|
|
3
|
+
/** Evaluate image refs in step input against policy config. @category Policies */
|
|
4
|
+
export function evaluateImageRefsPre(input, config) {
|
|
5
|
+
const refs = collectImageRefs(input);
|
|
6
|
+
if (config.maxImageRefsPerStep !== undefined && refs.length > config.maxImageRefsPerStep) {
|
|
7
|
+
return `Image ref count ${refs.length} exceeds maxImageRefsPerStep (${config.maxImageRefsPerStep})`;
|
|
8
|
+
}
|
|
9
|
+
for (const { path, ref } of refs) {
|
|
10
|
+
if (config.allowedInputKinds && !config.allowedInputKinds.includes(ref.kind)) {
|
|
11
|
+
return `Image ref at ${path} has disallowed kind '${ref.kind}'`;
|
|
12
|
+
}
|
|
13
|
+
if (ref.kind === IMAGE_REF_KINDS.URL) {
|
|
14
|
+
if (config.allowRemoteUrls === false) {
|
|
15
|
+
return `Remote URL image ref at ${path} is not allowed`;
|
|
16
|
+
}
|
|
17
|
+
const host = imageRefUrlHostname(ref);
|
|
18
|
+
if (config.allowedUrlDomains?.length && host && !config.allowedUrlDomains.includes(host)) {
|
|
19
|
+
return `URL domain '${host}' at ${path} is not in allowedUrlDomains`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const sizeBytes = "sizeBytes" in ref ? ref.sizeBytes : undefined;
|
|
23
|
+
if (sizeBytes !== undefined && config.maxInputBytes !== undefined && sizeBytes > config.maxInputBytes) {
|
|
24
|
+
return `Image ref at ${path} exceeds maxInputBytes`;
|
|
25
|
+
}
|
|
26
|
+
const mediaType = "mediaType" in ref ? ref.mediaType : undefined;
|
|
27
|
+
if (config.allowSvg === false && isSvgHint(mediaType)) {
|
|
28
|
+
return `SVG input at ${path} is not allowed`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (config.requireStripMetadata === true && input.output && typeof input.output === "object") {
|
|
32
|
+
const out = input.output;
|
|
33
|
+
if (out.stripMetadata === false || out.preserveMetadata === true) {
|
|
34
|
+
return "Metadata retention is not allowed by image-policy";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
/** Evaluate image output against policy config. @category Policies */
|
|
40
|
+
export function evaluateImageRefsPost(output, config) {
|
|
41
|
+
if (output === null || typeof output !== "object")
|
|
42
|
+
return undefined;
|
|
43
|
+
const refs = collectImageRefs(output);
|
|
44
|
+
for (const { path, ref } of refs) {
|
|
45
|
+
const sizeBytes = "sizeBytes" in ref ? ref.sizeBytes : undefined;
|
|
46
|
+
if (sizeBytes !== undefined && config.maxOutputBytes !== undefined && sizeBytes > config.maxOutputBytes) {
|
|
47
|
+
return `Output image ref at ${path} exceeds maxOutputBytes`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const info = output.info;
|
|
51
|
+
if (info) {
|
|
52
|
+
if (info.sizeBytes !== undefined && config.maxOutputBytes !== undefined && info.sizeBytes > config.maxOutputBytes) {
|
|
53
|
+
return "Output sizeBytes exceeds maxOutputBytes";
|
|
54
|
+
}
|
|
55
|
+
if (info.width !== undefined &&
|
|
56
|
+
info.height !== undefined &&
|
|
57
|
+
config.maxPixels !== undefined &&
|
|
58
|
+
info.width * info.height > config.maxPixels) {
|
|
59
|
+
return "Output dimensions exceed maxPixels";
|
|
60
|
+
}
|
|
61
|
+
if (info.width !== undefined && config.maxWidth !== undefined && info.width > config.maxWidth) {
|
|
62
|
+
return "Output width exceeds maxWidth";
|
|
63
|
+
}
|
|
64
|
+
if (info.height !== undefined && config.maxHeight !== undefined && info.height > config.maxHeight) {
|
|
65
|
+
return "Output height exceeds maxHeight";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const formats = collectOutputFormatHints(output);
|
|
69
|
+
for (const { path, format } of formats) {
|
|
70
|
+
if (config.denyRawOutput === true && format === "raw") {
|
|
71
|
+
return `Raw output format at ${path} is denied`;
|
|
72
|
+
}
|
|
73
|
+
if (config.allowedOutputFormats &&
|
|
74
|
+
!config.allowedOutputFormats.includes(format)) {
|
|
75
|
+
return `Output format '${format}' at ${path} is not allowed`;
|
|
76
|
+
}
|
|
77
|
+
if (config.allowSvg === false && isSvgHint(format)) {
|
|
78
|
+
return `SVG output at ${path} is not allowed`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=image-policy-eval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-policy-eval.js","sourceRoot":"","sources":["../src/image-policy-eval.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,SAAS,GACV,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAmBjE,kFAAkF;AAClF,MAAM,UAAU,oBAAoB,CAClC,KAA8B,EAC9B,MAAyB;IAEzB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACpC,IAAI,MAAM,CAAC,mBAAmB,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;QACzF,OAAO,mBAAmB,IAAI,CAAC,MAAM,iCAAiC,MAAM,CAAC,mBAAmB,GAAG,CAAA;IACrG,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;QACjC,IAAI,MAAM,CAAC,iBAAiB,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7E,OAAO,gBAAgB,IAAI,yBAAyB,GAAG,CAAC,IAAI,GAAG,CAAA;QACjE,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,GAAG,EAAE,CAAC;YACrC,IAAI,MAAM,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;gBACrC,OAAO,2BAA2B,IAAI,iBAAiB,CAAA;YACzD,CAAC;YACD,MAAM,IAAI,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAA;YACrC,IAAI,MAAM,CAAC,iBAAiB,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzF,OAAO,eAAe,IAAI,QAAQ,IAAI,8BAA8B,CAAA;YACtE,CAAC;QACH,CAAC;QACD,MAAM,SAAS,GAAG,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QAChE,IAAI,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,IAAI,SAAS,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;YACtG,OAAO,gBAAgB,IAAI,wBAAwB,CAAA;QACrD,CAAC;QACD,MAAM,SAAS,GAAG,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QAChE,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;YACtD,OAAO,gBAAgB,IAAI,iBAAiB,CAAA;QAC9C,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,oBAAoB,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7F,MAAM,GAAG,GAAG,KAAK,CAAC,MAAiE,CAAA;QACnF,IAAI,GAAG,CAAC,aAAa,KAAK,KAAK,IAAI,GAAG,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;YACjE,OAAO,mDAAmD,CAAA;QAC5D,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CACnC,MAAe,EACf,MAAyB;IAEzB,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAEnE,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACrC,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QAChE,IAAI,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,IAAI,SAAS,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;YACxG,OAAO,uBAAuB,IAAI,yBAAyB,CAAA;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAI,MAA8F,CAAC,IAAI,CAAA;IACjH,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,IAAI,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;YAClH,OAAO,yCAAyC,CAAA;QAClD,CAAC;QACD,IACE,IAAI,CAAC,KAAK,KAAK,SAAS;YACxB,IAAI,CAAC,MAAM,KAAK,SAAS;YACzB,MAAM,CAAC,SAAS,KAAK,SAAS;YAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAC3C,CAAC;YACD,OAAO,oCAAoC,CAAA;QAC7C,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC9F,OAAO,+BAA+B,CAAA;QACxC,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YAClG,OAAO,iCAAiC,CAAA;QAC1C,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAA;IAChD,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACvC,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACtD,OAAO,wBAAwB,IAAI,YAAY,CAAA;QACjD,CAAC;QACD,IACE,MAAM,CAAC,oBAAoB;YAC3B,CAAC,MAAM,CAAC,oBAAoB,CAAC,QAAQ,CAAC,MAAsD,CAAC,EAC7F,CAAC;YACD,OAAO,kBAAkB,MAAM,QAAQ,IAAI,iBAAiB,CAAA;QAC9D,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACnD,OAAO,iBAAiB,IAAI,iBAAiB,CAAA;QAC/C,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @executioncontrolprotocol/image-policy — generic ImageRef governance. @category Policies */
|
|
2
|
+
export declare const imagePolicy: import("@executioncontrolprotocol/core").PolicyDefinition;
|
|
3
|
+
export { evaluateImageRefsPre, evaluateImageRefsPost } from "./image-policy-eval.js";
|
|
4
|
+
export type { ImagePolicyConfig } from "./image-policy-eval.js";
|
|
5
|
+
/** Register `@executioncontrolprotocol/image-policy`. @category Policies */
|
|
6
|
+
export declare function registerImagePolicy(registry?: import("@executioncontrolprotocol/core").Registry): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=image-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-policy.d.ts","sourceRoot":"","sources":["../src/image-policy.ts"],"names":[],"mappings":"AAmBA,+FAA+F;AAC/F,eAAO,MAAM,WAAW,2DAqCd,CAAA;AAEV,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACpF,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,4EAA4E;AAC5E,wBAAsB,mBAAmB,CAAC,QAAQ,oDAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { definePolicy, globalRegistry, hook } from "@executioncontrolprotocol/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { evaluateImageRefsPost, evaluateImageRefsPre } from "./image-policy-eval.js";
|
|
4
|
+
function policyHook(event, fn) {
|
|
5
|
+
return hook(event, (lifecycleCtx) => fn(lifecycleCtx));
|
|
6
|
+
}
|
|
7
|
+
/** @executioncontrolprotocol/image-policy — generic ImageRef governance. @category Policies */
|
|
8
|
+
export const imagePolicy = definePolicy("@executioncontrolprotocol", "image-policy")
|
|
9
|
+
.withConfig({
|
|
10
|
+
allowedInputKinds: z
|
|
11
|
+
.array(z.enum(["artifact", "file", "url", "buffer"]))
|
|
12
|
+
.optional(),
|
|
13
|
+
allowedOutputFormats: z
|
|
14
|
+
.array(z.enum(["jpeg", "png", "webp", "avif", "tiff", "gif", "raw"]))
|
|
15
|
+
.optional(),
|
|
16
|
+
maxImageRefsPerStep: z.number().optional(),
|
|
17
|
+
maxInputBytes: z.number().optional(),
|
|
18
|
+
maxOutputBytes: z.number().optional(),
|
|
19
|
+
maxPixels: z.number().optional(),
|
|
20
|
+
maxWidth: z.number().optional(),
|
|
21
|
+
maxHeight: z.number().optional(),
|
|
22
|
+
allowSvg: z.boolean().optional(),
|
|
23
|
+
allowRemoteUrls: z.boolean().optional(),
|
|
24
|
+
allowedUrlDomains: z.array(z.string()).optional(),
|
|
25
|
+
requireStripMetadata: z.boolean().optional(),
|
|
26
|
+
denyRawOutput: z.boolean().optional(),
|
|
27
|
+
})
|
|
28
|
+
.withHooks([
|
|
29
|
+
policyHook("policy:pre", (ctx) => {
|
|
30
|
+
const reason = evaluateImageRefsPre(ctx.input, ctx.config);
|
|
31
|
+
if (reason) {
|
|
32
|
+
return { type: "deny", reason, code: "IMAGE_POLICY_DENIED" };
|
|
33
|
+
}
|
|
34
|
+
return { type: "allow" };
|
|
35
|
+
}),
|
|
36
|
+
policyHook("policy:post", (ctx) => {
|
|
37
|
+
if (ctx.output === undefined)
|
|
38
|
+
return { type: "allow" };
|
|
39
|
+
const reason = evaluateImageRefsPost(ctx.output, ctx.config);
|
|
40
|
+
if (reason) {
|
|
41
|
+
return { type: "deny", reason, code: "IMAGE_POLICY_DENIED" };
|
|
42
|
+
}
|
|
43
|
+
return { type: "allow" };
|
|
44
|
+
}),
|
|
45
|
+
])
|
|
46
|
+
.build();
|
|
47
|
+
export { evaluateImageRefsPre, evaluateImageRefsPost } from "./image-policy-eval.js";
|
|
48
|
+
/** Register `@executioncontrolprotocol/image-policy`. @category Policies */
|
|
49
|
+
export async function registerImagePolicy(registry = globalRegistry) {
|
|
50
|
+
if (!registry.getPolicy("@executioncontrolprotocol/image-policy")) {
|
|
51
|
+
await registry.registerPolicy(imagePolicy);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=image-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-policy.js","sourceRoot":"","sources":["../src/image-policy.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** @executioncontrolprotocol/budget policy definition. @category Policies */
|
|
2
|
+
export declare const budgetPolicy: import("@executioncontrolprotocol/core").PolicyDefinition;
|
|
3
|
+
/** @executioncontrolprotocol/approval policy. @category Policies */
|
|
4
|
+
export declare const approvalPolicy: import("@executioncontrolprotocol/core").PolicyDefinition;
|
|
5
|
+
/** @executioncontrolprotocol/state-control policy. @category Policies */
|
|
6
|
+
export declare const stateControlPolicy: import("@executioncontrolprotocol/core").PolicyDefinition;
|
|
7
|
+
export { registryControlPolicy, registerRegistryControlPolicy, REGISTRY_CONTROL_POLICY_ID, type RegistryControlPolicyConfig, } from "./registry-control.js";
|
|
8
|
+
export { imagePolicy, evaluateImageRefsPre, evaluateImageRefsPost, registerImagePolicy, type ImagePolicyConfig, } from "./image-policy.js";
|
|
9
|
+
/** Register all standard policies. @category Policies */
|
|
10
|
+
export declare function registerStandardPolicies(registry?: import("@executioncontrolprotocol/core").Registry): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAsDA,6EAA6E;AAC7E,eAAO,MAAM,YAAY,2DAcf,CAAA;AAEV,oEAAoE;AACpE,eAAO,MAAM,cAAc,2DAajB,CAAA;AASV,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,2DAwErB,CAAA;AAEV,OAAO,EACL,qBAAqB,EACrB,6BAA6B,EAC7B,0BAA0B,EAC1B,KAAK,2BAA2B,GACjC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAA;AAE1B,yDAAyD;AACzD,wBAAsB,wBAAwB,CAAC,QAAQ,oDAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { definePolicy, hook, globalRegistry } from "@executioncontrolprotocol/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { registerRegistryControlPolicy } from "./registry-control.js";
|
|
4
|
+
function policyHook(event, fn) {
|
|
5
|
+
return hook(event, (lifecycleCtx) => fn(lifecycleCtx));
|
|
6
|
+
}
|
|
7
|
+
/** Budget dimensions enforced by the budget policy. */
|
|
8
|
+
const BUDGET_LIMITS = [
|
|
9
|
+
{ config: "maxModelCalls", usage: "modelCalls", code: "BUDGET_MODEL_CALLS", label: "model calls" },
|
|
10
|
+
{ config: "maxCostUsd", usage: "costUsd", code: "BUDGET_COST_USD", label: "cost (USD)" },
|
|
11
|
+
{ config: "maxTokens", usage: "tokens", code: "BUDGET_TOKENS", label: "tokens" },
|
|
12
|
+
{ config: "maxRetries", usage: "retries", code: "BUDGET_RETRIES", label: "retries" },
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Evaluate every configured budget dimension against the usage ledger.
|
|
16
|
+
* `inclusive` denies when usage has already reached the limit (`policy:pre`,
|
|
17
|
+
* before more work is done); otherwise denies only when the limit is exceeded
|
|
18
|
+
* (`policy:post`, after work has completed).
|
|
19
|
+
*/
|
|
20
|
+
function evaluateBudget(config, usage, inclusive) {
|
|
21
|
+
for (const limit of BUDGET_LIMITS) {
|
|
22
|
+
const max = config[limit.config];
|
|
23
|
+
if (max === undefined)
|
|
24
|
+
continue;
|
|
25
|
+
const used = usage[limit.usage];
|
|
26
|
+
const overBudget = inclusive ? used >= max : used > max;
|
|
27
|
+
if (overBudget) {
|
|
28
|
+
return {
|
|
29
|
+
type: "deny",
|
|
30
|
+
reason: `Budget exceeded for ${limit.label}: ${used} of ${max}`,
|
|
31
|
+
code: limit.code,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { type: "allow" };
|
|
36
|
+
}
|
|
37
|
+
/** @executioncontrolprotocol/budget policy definition. @category Policies */
|
|
38
|
+
export const budgetPolicy = definePolicy("@executioncontrolprotocol", "budget")
|
|
39
|
+
.withConfig({
|
|
40
|
+
maxCostUsd: z.number().optional(),
|
|
41
|
+
maxModelCalls: z.number().optional(),
|
|
42
|
+
maxRetries: z.number().optional(),
|
|
43
|
+
maxTokens: z.number().optional(),
|
|
44
|
+
})
|
|
45
|
+
.withHooks([
|
|
46
|
+
policyHook("policy:pre", (ctx) => evaluateBudget(ctx.config, ctx.usage, true)),
|
|
47
|
+
policyHook("policy:post", (ctx) => evaluateBudget(ctx.config, ctx.usage, false)),
|
|
48
|
+
// `policy:finally` cannot change the step outcome; it is reserved for
|
|
49
|
+
// usage reconciliation/reporting. No-op until a reporting sink is bound.
|
|
50
|
+
policyHook("policy:finally", () => undefined),
|
|
51
|
+
])
|
|
52
|
+
.build();
|
|
53
|
+
/** @executioncontrolprotocol/approval policy. @category Policies */
|
|
54
|
+
export const approvalPolicy = definePolicy("@executioncontrolprotocol", "approval")
|
|
55
|
+
.withConfig({
|
|
56
|
+
requireApprovalFor: z.array(z.string()).default([]),
|
|
57
|
+
})
|
|
58
|
+
.withHooks([
|
|
59
|
+
policyHook("policy:pre", (ctx) => {
|
|
60
|
+
const list = ctx.config.requireApprovalFor ?? [];
|
|
61
|
+
if (list.includes(ctx.step.capabilityId)) {
|
|
62
|
+
return { type: "pause", reason: "Approval required" };
|
|
63
|
+
}
|
|
64
|
+
return { type: "allow" };
|
|
65
|
+
}),
|
|
66
|
+
])
|
|
67
|
+
.build();
|
|
68
|
+
/** Whether `path` is covered by `prefix` (exact or dotted descendant). */
|
|
69
|
+
function pathMatches(path, prefix) {
|
|
70
|
+
return path === prefix || path.startsWith(`${prefix}.`);
|
|
71
|
+
}
|
|
72
|
+
/** @executioncontrolprotocol/state-control policy. @category Policies */
|
|
73
|
+
export const stateControlPolicy = definePolicy("@executioncontrolprotocol", "state-control")
|
|
74
|
+
.withConfig({
|
|
75
|
+
allowedMutablePaths: z.array(z.string()).optional(),
|
|
76
|
+
deniedMutablePaths: z.array(z.string()).optional(),
|
|
77
|
+
allowedMutationOps: z
|
|
78
|
+
.array(z.enum(["set", "replace", "merge", "append"]))
|
|
79
|
+
.optional(),
|
|
80
|
+
requireReason: z.boolean().optional(),
|
|
81
|
+
maxMutationsPerStep: z.number().optional(),
|
|
82
|
+
})
|
|
83
|
+
.withHooks([
|
|
84
|
+
policyHook("policy:pre", (ctx) => {
|
|
85
|
+
const denied = ctx.config.deniedMutablePaths;
|
|
86
|
+
const allowed = ctx.config.allowedMutablePaths;
|
|
87
|
+
for (const h of ctx.mutableStateHandles ?? []) {
|
|
88
|
+
const path = typeof h === "string" ? h : h.path;
|
|
89
|
+
// Denied paths win over allowed paths.
|
|
90
|
+
if (denied?.some((d) => pathMatches(path, d))) {
|
|
91
|
+
return {
|
|
92
|
+
type: "deny",
|
|
93
|
+
reason: `Mutable path is denied: ${path}`,
|
|
94
|
+
code: "STATE_PATH_DENIED",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (allowed && !allowed.some((a) => pathMatches(path, a))) {
|
|
98
|
+
return {
|
|
99
|
+
type: "deny",
|
|
100
|
+
reason: `Mutable path not allowed: ${path}`,
|
|
101
|
+
code: "STATE_PATH_NOT_ALLOWED",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { type: "allow" };
|
|
106
|
+
}),
|
|
107
|
+
policyHook("policy:post", (ctx) => {
|
|
108
|
+
const pending = ctx.pendingMutations ?? [];
|
|
109
|
+
const max = ctx.config.maxMutationsPerStep;
|
|
110
|
+
if (max !== undefined && pending.length > max) {
|
|
111
|
+
return {
|
|
112
|
+
type: "deny",
|
|
113
|
+
reason: `Too many mutations in step: ${pending.length} of ${max}`,
|
|
114
|
+
code: "STATE_MAX_MUTATIONS",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const allowedOps = ctx.config.allowedMutationOps;
|
|
118
|
+
if (allowedOps) {
|
|
119
|
+
const disallowed = pending.find((m) => !allowedOps.includes(m.op));
|
|
120
|
+
if (disallowed) {
|
|
121
|
+
return {
|
|
122
|
+
type: "deny",
|
|
123
|
+
reason: `Mutation op not allowed: ${disallowed.op}`,
|
|
124
|
+
code: "STATE_OP_NOT_ALLOWED",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (ctx.config.requireReason === true) {
|
|
129
|
+
const missing = pending.find((m) => !m.reason || m.reason.trim() === "");
|
|
130
|
+
if (missing) {
|
|
131
|
+
return {
|
|
132
|
+
type: "deny",
|
|
133
|
+
reason: `Mutation to '${missing.path}' requires a reason`,
|
|
134
|
+
code: "STATE_REASON_REQUIRED",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { type: "allow" };
|
|
139
|
+
}),
|
|
140
|
+
])
|
|
141
|
+
.build();
|
|
142
|
+
export { registryControlPolicy, registerRegistryControlPolicy, REGISTRY_CONTROL_POLICY_ID, } from "./registry-control.js";
|
|
143
|
+
export { imagePolicy, evaluateImageRefsPre, evaluateImageRefsPost, registerImagePolicy, } from "./image-policy.js";
|
|
144
|
+
/** Register all standard policies. @category Policies */
|
|
145
|
+
export async function registerStandardPolicies(registry = globalRegistry) {
|
|
146
|
+
if (!registry.getPolicy("@executioncontrolprotocol/budget")) {
|
|
147
|
+
await registry.registerPolicy(budgetPolicy);
|
|
148
|
+
}
|
|
149
|
+
if (!registry.getPolicy("@executioncontrolprotocol/approval")) {
|
|
150
|
+
await registry.registerPolicy(approvalPolicy);
|
|
151
|
+
}
|
|
152
|
+
if (!registry.getPolicy("@executioncontrolprotocol/state-control")) {
|
|
153
|
+
await registry.registerPolicy(stateControlPolicy);
|
|
154
|
+
}
|
|
155
|
+
await registerRegistryControlPolicy(registry);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Config for `@executioncontrolprotocol/registry-control`. @category Policies */
|
|
2
|
+
export interface RegistryControlPolicyConfig {
|
|
3
|
+
/** Allowed extension namespace patterns. */
|
|
4
|
+
allowedExtensionNamespaces?: string[];
|
|
5
|
+
/** Denied extension namespace patterns (wins over allow). */
|
|
6
|
+
deniedExtensionNamespaces?: string[];
|
|
7
|
+
/** Whether dynamic extension registration is permitted. */
|
|
8
|
+
allowDynamicExtensionRegistration?: boolean;
|
|
9
|
+
/** Whether auto-bind after registration is permitted. */
|
|
10
|
+
allowAutoBind?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const POLICY_ID = "@executioncontrolprotocol/registry-control";
|
|
13
|
+
/** @executioncontrolprotocol/registry-control — governs dynamic extension registration. @category Policies */
|
|
14
|
+
export declare const registryControlPolicy: import("@executioncontrolprotocol/core").PolicyDefinition;
|
|
15
|
+
export { POLICY_ID as REGISTRY_CONTROL_POLICY_ID };
|
|
16
|
+
/** Register `@executioncontrolprotocol/registry-control` on the global registry. */
|
|
17
|
+
export declare function registerRegistryControlPolicy(registry?: import("@executioncontrolprotocol/core").Registry): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=registry-control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-control.d.ts","sourceRoot":"","sources":["../src/registry-control.ts"],"names":[],"mappings":"AAkBA,kFAAkF;AAClF,MAAM,WAAW,2BAA2B;IAC1C,4CAA4C;IAC5C,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAA;IACrC,6DAA6D;IAC7D,yBAAyB,CAAC,EAAE,MAAM,EAAE,CAAA;IACpC,2DAA2D;IAC3D,iCAAiC,CAAC,EAAE,OAAO,CAAA;IAC3C,yDAAyD;IACzD,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,QAAA,MAAM,SAAS,+CAA+C,CAAA;AAE9D,8GAA8G;AAC9G,eAAO,MAAM,qBAAqB,2DA0DxB,CAAA;AAEV,OAAO,EAAE,SAAS,IAAI,0BAA0B,EAAE,CAAA;AAElD,oFAAoF;AACpF,wBAAsB,6BAA6B,CAAC,QAAQ,oDAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5F"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { definePolicy, globalRegistry, hook, matchesAnyNamespace } from "@executioncontrolprotocol/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
function policyHook(event, fn) {
|
|
4
|
+
return hook(event, (lifecycleCtx) => fn(lifecycleCtx));
|
|
5
|
+
}
|
|
6
|
+
const POLICY_ID = "@executioncontrolprotocol/registry-control";
|
|
7
|
+
/** @executioncontrolprotocol/registry-control — governs dynamic extension registration. @category Policies */
|
|
8
|
+
export const registryControlPolicy = definePolicy("@executioncontrolprotocol", "registry-control")
|
|
9
|
+
.withConfig({
|
|
10
|
+
allowedExtensionNamespaces: z.array(z.string()).optional(),
|
|
11
|
+
deniedExtensionNamespaces: z.array(z.string()).default([]),
|
|
12
|
+
allowDynamicExtensionRegistration: z.boolean().default(true),
|
|
13
|
+
allowAutoBind: z.boolean().default(true),
|
|
14
|
+
})
|
|
15
|
+
.withHooks([
|
|
16
|
+
policyHook("policy:pre", (ctx) => {
|
|
17
|
+
const req = ctx.registryRequest;
|
|
18
|
+
if (!req)
|
|
19
|
+
return { type: "allow" };
|
|
20
|
+
if (req.kind !== "extension") {
|
|
21
|
+
return {
|
|
22
|
+
type: "deny",
|
|
23
|
+
reason: "Dynamic policy and runtime registration is not allowed",
|
|
24
|
+
code: "REGISTRY_KIND_DENIED",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const allowDynamic = ctx.config.allowDynamicExtensionRegistration !== false;
|
|
28
|
+
if (!allowDynamic) {
|
|
29
|
+
return {
|
|
30
|
+
type: "deny",
|
|
31
|
+
reason: "Dynamic extension registration is disabled",
|
|
32
|
+
code: "REGISTRY_DYNAMIC_DISABLED",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (req.autoBindRequested && ctx.config.allowAutoBind === false) {
|
|
36
|
+
return {
|
|
37
|
+
type: "deny",
|
|
38
|
+
reason: "Auto-bind after registration is not allowed",
|
|
39
|
+
code: "REGISTRY_AUTOBIND_DENIED",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const denied = ctx.config.deniedExtensionNamespaces ?? [];
|
|
43
|
+
if (denied.length > 0 && matchesAnyNamespace(req.id, denied)) {
|
|
44
|
+
return {
|
|
45
|
+
type: "deny",
|
|
46
|
+
reason: `Extension namespace is denied: ${req.id}`,
|
|
47
|
+
code: "REGISTRY_NAMESPACE_DENIED",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const allowed = ctx.config.allowedExtensionNamespaces;
|
|
51
|
+
if (allowed && allowed.length > 0 && !matchesAnyNamespace(req.id, allowed)) {
|
|
52
|
+
return {
|
|
53
|
+
type: "deny",
|
|
54
|
+
reason: `Extension namespace is not allowed: ${req.id}`,
|
|
55
|
+
code: "REGISTRY_NAMESPACE_NOT_ALLOWED",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return { type: "allow" };
|
|
59
|
+
}),
|
|
60
|
+
])
|
|
61
|
+
.build();
|
|
62
|
+
export { POLICY_ID as REGISTRY_CONTROL_POLICY_ID };
|
|
63
|
+
/** Register `@executioncontrolprotocol/registry-control` on the global registry. */
|
|
64
|
+
export async function registerRegistryControlPolicy(registry = globalRegistry) {
|
|
65
|
+
if (!registry.getPolicy(POLICY_ID)) {
|
|
66
|
+
await registry.registerPolicy(registryControlPolicy);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=registry-control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-control.js","sourceRoot":"","sources":["../src/registry-control.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@executioncontrolprotocol/policies",
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Standard ECP policies",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -b"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@executioncontrolprotocol/core": "^0.10.0",
|
|
24
|
+
"@executioncontrolprotocol/types": "^0.10.0",
|
|
25
|
+
"zod": "^3.24.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@executioncontrolprotocol/core": "0.10.0",
|
|
29
|
+
"@executioncontrolprotocol/types": "0.10.0",
|
|
30
|
+
"typescript": "^5.7.0",
|
|
31
|
+
"zod": "^3.24.0"
|
|
32
|
+
}
|
|
33
|
+
}
|