@zapier/policy-context 0.10.0 → 1.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/dist/index.cjs +265 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +190 -32
- package/dist/index.d.ts +190 -32
- package/dist/index.js +259 -113
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -21,14 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AccessLevelSchema: () => AccessLevelSchema,
|
|
24
|
+
ActionRunContextInputSchema: () => ActionRunContextInputSchema,
|
|
24
25
|
ActionRunContextSchema: () => ActionRunContextSchema,
|
|
26
|
+
ActionTypeSchema: () => ActionTypeSchema,
|
|
25
27
|
BuildActionRunContextOptionsSchema: () => BuildActionRunContextOptionsSchema,
|
|
26
28
|
BuildHttpRequestContextOptionsSchema: () => BuildHttpRequestContextOptionsSchema,
|
|
27
29
|
DEFAULT_PORTS: () => DEFAULT_PORTS,
|
|
28
30
|
HttpRequestContextSchema: () => HttpRequestContextSchema,
|
|
29
31
|
IGNORED_HEADERS: () => IGNORED_HEADERS,
|
|
30
|
-
JsonValueSchema: () => import_policy_schema.JsonValueSchema,
|
|
31
32
|
ParsedUrlSchema: () => ParsedUrlSchema,
|
|
33
|
+
READ_ACTION_TYPES: () => READ_ACTION_TYPES,
|
|
34
|
+
READ_HTTP_METHODS: () => READ_HTTP_METHODS,
|
|
32
35
|
RequestContextSchema: () => RequestContextSchema,
|
|
33
36
|
buildActionResource: () => buildActionResource,
|
|
34
37
|
buildActionRunContext: () => buildActionRunContext,
|
|
@@ -39,6 +42,8 @@ __export(index_exports, {
|
|
|
39
42
|
buildExactHttpConditions: () => buildExactHttpConditions,
|
|
40
43
|
buildHttpRequestContext: () => buildHttpRequestContext,
|
|
41
44
|
buildUrlString: () => buildUrlString,
|
|
45
|
+
isWriteRequest: () => isWriteRequest,
|
|
46
|
+
parseActionResource: () => parseActionResource,
|
|
42
47
|
parseUrl: () => parseUrl,
|
|
43
48
|
toExactPolicy: () => toExactPolicy
|
|
44
49
|
});
|
|
@@ -46,13 +51,20 @@ module.exports = __toCommonJS(index_exports);
|
|
|
46
51
|
|
|
47
52
|
// src/types.ts
|
|
48
53
|
var import_zod = require("zod");
|
|
49
|
-
var
|
|
54
|
+
var import_zod_to_openapi = require("@asteasolutions/zod-to-openapi");
|
|
55
|
+
(0, import_zod_to_openapi.extendZodWithOpenApi)(import_zod.z);
|
|
50
56
|
var ParsedUrlSchema = import_zod.z.object({
|
|
51
|
-
scheme: import_zod.z.string(),
|
|
52
|
-
host: import_zod.z.string(),
|
|
53
|
-
port: import_zod.z.number()
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
scheme: import_zod.z.string().openapi({ description: 'URL scheme, e.g. "https"' }),
|
|
58
|
+
host: import_zod.z.string().openapi({ description: 'Hostname, e.g. "api.example.com"' }),
|
|
59
|
+
port: import_zod.z.number().int().openapi({
|
|
60
|
+
description: "Port number (defaults to 443 for https, 80 for http)"
|
|
61
|
+
}),
|
|
62
|
+
path: import_zod.z.string().openapi({ description: 'URL path, e.g. "/v1/foo"' }),
|
|
63
|
+
query: import_zod.z.record(import_zod.z.string(), import_zod.z.array(import_zod.z.string())).openapi({
|
|
64
|
+
description: "Query parameters as key to string array mapping"
|
|
65
|
+
})
|
|
66
|
+
}).openapi("ParsedUrl", {
|
|
67
|
+
description: "Parsed URL components for policy condition matching"
|
|
56
68
|
});
|
|
57
69
|
var DEFAULT_PORTS = {
|
|
58
70
|
http: 80,
|
|
@@ -87,34 +99,137 @@ function buildUrlString(parsed) {
|
|
|
87
99
|
return `${scheme}://${host}${portString}${path}${queryString ? "?" + queryString : ""}`;
|
|
88
100
|
}
|
|
89
101
|
var HttpRequestContextSchema = import_zod.z.object({
|
|
90
|
-
request_type: import_zod.z.literal("http_request"),
|
|
91
|
-
method: import_zod.z.string(),
|
|
102
|
+
request_type: import_zod.z.literal("http_request").openapi({ description: "Context type discriminator" }),
|
|
103
|
+
method: import_zod.z.string().max(10).transform((m) => m.toUpperCase()).openapi({ description: "HTTP method" }),
|
|
92
104
|
/** Parsed URL components for policy condition matching */
|
|
93
105
|
url: ParsedUrlSchema,
|
|
94
106
|
/** Filtered headers (IGNORED_HEADERS excluded, keys lowercased) */
|
|
95
|
-
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string())
|
|
107
|
+
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).openapi({
|
|
108
|
+
description: "Filtered headers (IGNORED_HEADERS excluded, keys lowercased)"
|
|
109
|
+
}),
|
|
96
110
|
/** Raw body string */
|
|
97
|
-
body: import_zod.z.string().nullable(),
|
|
98
|
-
/**
|
|
99
|
-
|
|
111
|
+
body: import_zod.z.string().max(65536).nullable().openapi({ description: "Raw body string" }),
|
|
112
|
+
/**
|
|
113
|
+
* Parsed JSON body. Authored as `z.unknown().pipe(z.json())` so
|
|
114
|
+
* zod-to-openapi sees the outer `z.unknown()` and emits a permissive
|
|
115
|
+
* field (no recursive `$ref`, no type), while the inner `z.json()`
|
|
116
|
+
* still rejects non-JSON values (`Date`, `undefined`, functions) at
|
|
117
|
+
* parse time. Same inferred `JsonValue` type either way.
|
|
118
|
+
*/
|
|
119
|
+
body_json: import_zod.z.unknown().pipe(import_zod.z.json()).nullable().describe("Parsed JSON body (if applicable)"),
|
|
100
120
|
/** Zapier connection ID used for this request */
|
|
101
|
-
connection_id: import_zod.z.string().optional(),
|
|
121
|
+
connection_id: import_zod.z.string().max(255).optional().openapi({ description: "Zapier connection ID used for this request" }),
|
|
102
122
|
/** Optional human-readable reason for the request */
|
|
103
|
-
reason: import_zod.z.string().optional()
|
|
123
|
+
reason: import_zod.z.string().max(1024).optional().openapi({ description: "Optional human-readable reason for the request" })
|
|
124
|
+
}).openapi("HttpRequestContext");
|
|
125
|
+
var ActionTypeSchema = import_zod.z.enum([
|
|
126
|
+
"filter",
|
|
127
|
+
"read",
|
|
128
|
+
"read_bulk",
|
|
129
|
+
"run",
|
|
130
|
+
"search",
|
|
131
|
+
"search_and_write",
|
|
132
|
+
"search_or_write",
|
|
133
|
+
"write"
|
|
134
|
+
]).openapi("action_type", { description: "Canonical Zapier action type." });
|
|
135
|
+
var ACTION_RESOURCE_SEGMENT_PATTERN = /^[A-Za-z0-9._+-]+(?:@[A-Za-z0-9._+-]+)?$/;
|
|
136
|
+
function parseActionResource(resource) {
|
|
137
|
+
const segments = resource.split("/");
|
|
138
|
+
if (segments.length !== 4 || segments[0] !== "action") {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`action resource must be action/{selected_api}/{action_type}/{action_key}: got ${resource}`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const [, selectedApi, actionTypeRaw, actionKey] = segments;
|
|
144
|
+
if (!selectedApi || !actionTypeRaw || !actionKey) {
|
|
145
|
+
throw new Error(`action resource has empty segment: ${resource}`);
|
|
146
|
+
}
|
|
147
|
+
const actionType = ActionTypeSchema.safeParse(actionTypeRaw);
|
|
148
|
+
if (!actionType.success) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`action resource has unknown action_type "${actionTypeRaw}": ${resource}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (!ACTION_RESOURCE_SEGMENT_PATTERN.test(selectedApi)) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`action resource has invalid selected_api segment "${selectedApi}": ${resource}`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
if (!ACTION_RESOURCE_SEGMENT_PATTERN.test(actionKey)) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`action resource has invalid action_key segment "${actionKey}": ${resource}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
selected_api: selectedApi,
|
|
165
|
+
action_type: actionType.data,
|
|
166
|
+
action_key: actionKey
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
var ActionRunContextInputSchema = import_zod.z.object({
|
|
170
|
+
request_type: import_zod.z.literal("action_run").openapi({ description: "Context type discriminator" }),
|
|
171
|
+
resource: import_zod.z.string().max(1024).optional().openapi({
|
|
172
|
+
description: "Canonical action resource, e.g. action/Slack@1.0.0/write/send_message"
|
|
173
|
+
}),
|
|
174
|
+
selected_api: import_zod.z.string().max(255).optional().openapi({
|
|
175
|
+
deprecated: true,
|
|
176
|
+
description: "Legacy: app identifier, e.g. Slack@1.0.0. Prefer `resource`."
|
|
177
|
+
}),
|
|
178
|
+
action_type: ActionTypeSchema.optional().openapi({
|
|
179
|
+
deprecated: true,
|
|
180
|
+
description: "Legacy: canonical Zapier action type. Prefer `resource`."
|
|
181
|
+
}),
|
|
182
|
+
action_key: import_zod.z.string().max(255).optional().openapi({
|
|
183
|
+
deprecated: true,
|
|
184
|
+
description: "Legacy: action key, e.g. send_message. Prefer `resource`."
|
|
185
|
+
}),
|
|
186
|
+
connection_id: import_zod.z.string().max(255).optional().openapi({ description: "Zapier connection ID used for this request" }),
|
|
187
|
+
/** Action input parameters. See body_json above for the pipe rationale. */
|
|
188
|
+
inputs: import_zod.z.unknown().pipe(import_zod.z.json()).optional().describe("Action input parameters"),
|
|
189
|
+
reason: import_zod.z.string().max(1024).optional().openapi({ description: "Optional human-readable reason for the request" })
|
|
190
|
+
}).openapi("ActionRunContext", {
|
|
191
|
+
description: "Action run context. The canonical shape carries the action identity in a single `resource` field of the form `action/{selected_api}/{action_type}/{action_key}`. The legacy `{selected_api, action_type, action_key}` shape is also accepted on input during the migration window \u2014 approvalsapi normalizes it to the canonical form before storage."
|
|
104
192
|
});
|
|
105
|
-
var ActionRunContextSchema =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
193
|
+
var ActionRunContextSchema = ActionRunContextInputSchema.transform(
|
|
194
|
+
(input, ctx) => {
|
|
195
|
+
const resource = input.resource ?? (input.selected_api && input.action_type && input.action_key ? `action/${input.selected_api}/${input.action_type}/${input.action_key}` : void 0);
|
|
196
|
+
if (resource === void 0) {
|
|
197
|
+
ctx.addIssue({
|
|
198
|
+
code: "custom",
|
|
199
|
+
message: "action_run context requires either `resource` or all of `selected_api`/`action_type`/`action_key`"
|
|
200
|
+
});
|
|
201
|
+
return import_zod.z.NEVER;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
parseActionResource(resource);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
ctx.addIssue({
|
|
207
|
+
code: "custom",
|
|
208
|
+
message: err instanceof Error ? err.message : String(err)
|
|
209
|
+
});
|
|
210
|
+
return import_zod.z.NEVER;
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
request_type: "action_run",
|
|
214
|
+
resource,
|
|
215
|
+
...input.connection_id !== void 0 && {
|
|
216
|
+
connection_id: input.connection_id
|
|
217
|
+
},
|
|
218
|
+
...input.inputs !== void 0 && { inputs: input.inputs },
|
|
219
|
+
...input.reason !== void 0 && { reason: input.reason }
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
var RequestContextSchema = import_zod.z.union([HttpRequestContextSchema, ActionRunContextSchema]).openapi("RequestContext", {
|
|
224
|
+
description: "Union of request context shapes, keyed on `request_type`.",
|
|
225
|
+
discriminator: {
|
|
226
|
+
propertyName: "request_type",
|
|
227
|
+
mapping: {
|
|
228
|
+
http_request: "#/components/schemas/HttpRequestContext",
|
|
229
|
+
action_run: "#/components/schemas/ActionRunContext"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
113
232
|
});
|
|
114
|
-
var RequestContextSchema = import_zod.z.discriminatedUnion("request_type", [
|
|
115
|
-
HttpRequestContextSchema,
|
|
116
|
-
ActionRunContextSchema
|
|
117
|
-
]);
|
|
118
233
|
|
|
119
234
|
// src/constants.ts
|
|
120
235
|
var IGNORED_HEADERS = /* @__PURE__ */ new Set([
|
|
@@ -148,74 +263,6 @@ var IGNORED_HEADERS = /* @__PURE__ */ new Set([
|
|
|
148
263
|
|
|
149
264
|
// src/builders.ts
|
|
150
265
|
var import_zod2 = require("zod");
|
|
151
|
-
var BuildHttpRequestContextOptionsSchema = import_zod2.z.object({
|
|
152
|
-
method: import_zod2.z.string(),
|
|
153
|
-
/** Raw URL string. Will be normalized with https:// if no protocol present. */
|
|
154
|
-
url: import_zod2.z.string(),
|
|
155
|
-
/** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */
|
|
156
|
-
headers: import_zod2.z.record(
|
|
157
|
-
import_zod2.z.string(),
|
|
158
|
-
import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.string()), import_zod2.z.undefined()])
|
|
159
|
-
).optional(),
|
|
160
|
-
/** Raw body string */
|
|
161
|
-
body: import_zod2.z.string().nullable().optional(),
|
|
162
|
-
/** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */
|
|
163
|
-
body_json: import_policy_schema.JsonValueSchema.optional(),
|
|
164
|
-
/** Connection ID associated with this request */
|
|
165
|
-
connection_id: import_zod2.z.string().optional()
|
|
166
|
-
});
|
|
167
|
-
function buildHttpRequestContext(options) {
|
|
168
|
-
const rawUrl = options.url.includes("://") ? options.url : `https://${options.url}`;
|
|
169
|
-
const url = parseUrl(rawUrl);
|
|
170
|
-
const headers = {};
|
|
171
|
-
if (options.headers) {
|
|
172
|
-
for (const [key, value] of Object.entries(options.headers)) {
|
|
173
|
-
const lowerKey = key.toLowerCase();
|
|
174
|
-
if (!IGNORED_HEADERS.has(lowerKey) && typeof value === "string") {
|
|
175
|
-
headers[lowerKey] = value;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
let body_json = null;
|
|
180
|
-
if (options.body_json !== void 0) {
|
|
181
|
-
body_json = options.body_json;
|
|
182
|
-
} else if (options.body) {
|
|
183
|
-
const contentType = headers["content-type"];
|
|
184
|
-
const isJson = typeof contentType === "string" && (contentType.includes("application/json") || contentType.includes("application/") && contentType.includes("+json"));
|
|
185
|
-
if (isJson) {
|
|
186
|
-
try {
|
|
187
|
-
body_json = JSON.parse(options.body);
|
|
188
|
-
} catch {
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return HttpRequestContextSchema.parse({
|
|
193
|
-
request_type: "http_request",
|
|
194
|
-
method: options.method,
|
|
195
|
-
url,
|
|
196
|
-
headers,
|
|
197
|
-
body: options.body ?? null,
|
|
198
|
-
body_json,
|
|
199
|
-
connection_id: options.connection_id
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
var BuildActionRunContextOptionsSchema = import_zod2.z.object({
|
|
203
|
-
selected_api: import_zod2.z.string(),
|
|
204
|
-
action_type: import_zod2.z.string(),
|
|
205
|
-
action_key: import_zod2.z.string(),
|
|
206
|
-
connection_id: import_zod2.z.string().optional(),
|
|
207
|
-
inputs: import_policy_schema.JsonValueSchema.optional()
|
|
208
|
-
});
|
|
209
|
-
function buildActionRunContext(options) {
|
|
210
|
-
return ActionRunContextSchema.parse({
|
|
211
|
-
request_type: "action_run",
|
|
212
|
-
selected_api: options.selected_api,
|
|
213
|
-
action_type: options.action_type,
|
|
214
|
-
action_key: options.action_key,
|
|
215
|
-
connection_id: options.connection_id,
|
|
216
|
-
inputs: options.inputs
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
266
|
|
|
220
267
|
// src/conditions.ts
|
|
221
268
|
function buildExactHttpConditions(context) {
|
|
@@ -244,6 +291,12 @@ function buildExactHttpConditions(context) {
|
|
|
244
291
|
operator: "equals",
|
|
245
292
|
value: context.body_json
|
|
246
293
|
});
|
|
294
|
+
} else if (context.body !== null) {
|
|
295
|
+
conditions.push({
|
|
296
|
+
path: ["body"],
|
|
297
|
+
operator: "equals",
|
|
298
|
+
value: context.body
|
|
299
|
+
});
|
|
247
300
|
}
|
|
248
301
|
for (const [key, value] of Object.entries(context.headers)) {
|
|
249
302
|
if (!IGNORED_HEADERS.has(key.toLowerCase()) && typeof value === "string") {
|
|
@@ -267,7 +320,7 @@ function buildDomainHttpConditions(context) {
|
|
|
267
320
|
}
|
|
268
321
|
function buildExactActionConditions(context) {
|
|
269
322
|
const conditions = [];
|
|
270
|
-
if (context.inputs !== void 0 && context.inputs !== null
|
|
323
|
+
if (context.inputs !== void 0 && context.inputs !== null) {
|
|
271
324
|
conditions.push({
|
|
272
325
|
path: ["inputs"],
|
|
273
326
|
operator: "equals",
|
|
@@ -276,11 +329,91 @@ function buildExactActionConditions(context) {
|
|
|
276
329
|
}
|
|
277
330
|
return conditions;
|
|
278
331
|
}
|
|
279
|
-
function buildActionResource(
|
|
280
|
-
return `action/${
|
|
332
|
+
function buildActionResource(parts) {
|
|
333
|
+
return `action/${parts.selected_api}/${parts.action_type}/${parts.action_key}`;
|
|
281
334
|
}
|
|
282
|
-
function buildBroadActionResource(
|
|
283
|
-
return `action/${
|
|
335
|
+
function buildBroadActionResource(parts) {
|
|
336
|
+
return `action/${parts.selected_api}/${parts.action_type}/*`;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/builders.ts
|
|
340
|
+
var BuildHttpRequestContextOptionsSchema = import_zod2.z.object({
|
|
341
|
+
method: import_zod2.z.string(),
|
|
342
|
+
/** Raw URL string. Will be normalized with https:// if no protocol present. */
|
|
343
|
+
url: import_zod2.z.string(),
|
|
344
|
+
/** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */
|
|
345
|
+
headers: import_zod2.z.record(
|
|
346
|
+
import_zod2.z.string(),
|
|
347
|
+
import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.string()), import_zod2.z.undefined()])
|
|
348
|
+
).optional(),
|
|
349
|
+
/** Raw body string */
|
|
350
|
+
body: import_zod2.z.string().nullable().optional(),
|
|
351
|
+
/** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */
|
|
352
|
+
body_json: import_zod2.z.json().optional(),
|
|
353
|
+
/** Connection ID associated with this request */
|
|
354
|
+
connection_id: import_zod2.z.string().optional()
|
|
355
|
+
});
|
|
356
|
+
function buildHttpRequestContext(options) {
|
|
357
|
+
const parsed = BuildHttpRequestContextOptionsSchema.parse(options);
|
|
358
|
+
const rawUrl = parsed.url.includes("://") ? parsed.url : `https://${parsed.url}`;
|
|
359
|
+
const url = parseUrl(rawUrl);
|
|
360
|
+
const headers = {};
|
|
361
|
+
if (parsed.headers) {
|
|
362
|
+
for (const [key, value] of Object.entries(parsed.headers)) {
|
|
363
|
+
const lowerKey = key.toLowerCase();
|
|
364
|
+
if (!IGNORED_HEADERS.has(lowerKey) && typeof value === "string") {
|
|
365
|
+
headers[lowerKey] = value;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
let body_json = null;
|
|
370
|
+
if (parsed.body_json !== void 0) {
|
|
371
|
+
body_json = parsed.body_json;
|
|
372
|
+
} else if (parsed.body) {
|
|
373
|
+
const contentType = headers["content-type"];
|
|
374
|
+
const isJson = typeof contentType === "string" && (contentType.includes("application/json") || contentType.includes("application/") && contentType.includes("+json"));
|
|
375
|
+
if (isJson) {
|
|
376
|
+
try {
|
|
377
|
+
body_json = JSON.parse(parsed.body);
|
|
378
|
+
} catch {
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return HttpRequestContextSchema.parse({
|
|
383
|
+
request_type: "http_request",
|
|
384
|
+
method: parsed.method.toUpperCase(),
|
|
385
|
+
url,
|
|
386
|
+
headers,
|
|
387
|
+
body: parsed.body ?? null,
|
|
388
|
+
body_json,
|
|
389
|
+
connection_id: parsed.connection_id
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
var BuildActionRunContextOptionsSchema = import_zod2.z.object({
|
|
393
|
+
selected_api: import_zod2.z.string().regex(ACTION_RESOURCE_SEGMENT_PATTERN, {
|
|
394
|
+
message: "selected_api must contain only [A-Za-z0-9._@+-] (no globs, slashes, or whitespace)"
|
|
395
|
+
}),
|
|
396
|
+
action_type: ActionTypeSchema,
|
|
397
|
+
action_key: import_zod2.z.string().regex(ACTION_RESOURCE_SEGMENT_PATTERN, {
|
|
398
|
+
message: "action_key must contain only [A-Za-z0-9._@+-] (no globs, slashes, or whitespace)"
|
|
399
|
+
}),
|
|
400
|
+
connection_id: import_zod2.z.string().optional(),
|
|
401
|
+
inputs: import_zod2.z.json().optional(),
|
|
402
|
+
reason: import_zod2.z.string().optional()
|
|
403
|
+
});
|
|
404
|
+
function buildActionRunContext(options) {
|
|
405
|
+
const parsed = BuildActionRunContextOptionsSchema.parse(options);
|
|
406
|
+
return ActionRunContextSchema.parse({
|
|
407
|
+
request_type: "action_run",
|
|
408
|
+
resource: buildActionResource({
|
|
409
|
+
selected_api: parsed.selected_api,
|
|
410
|
+
action_type: parsed.action_type,
|
|
411
|
+
action_key: parsed.action_key
|
|
412
|
+
}),
|
|
413
|
+
connection_id: parsed.connection_id,
|
|
414
|
+
inputs: parsed.inputs,
|
|
415
|
+
reason: parsed.reason
|
|
416
|
+
});
|
|
284
417
|
}
|
|
285
418
|
|
|
286
419
|
// src/policies.ts
|
|
@@ -319,7 +452,7 @@ function actionContextToPolicy(context) {
|
|
|
319
452
|
statements.push({
|
|
320
453
|
effect: "allow",
|
|
321
454
|
permissions: ["can_execute"],
|
|
322
|
-
resources: [
|
|
455
|
+
resources: [context.resource],
|
|
323
456
|
conditions: buildExactActionConditions(context)
|
|
324
457
|
});
|
|
325
458
|
return { version: 2, statements };
|
|
@@ -333,9 +466,28 @@ function toExactPolicy(context) {
|
|
|
333
466
|
|
|
334
467
|
// src/connection-policy.ts
|
|
335
468
|
var import_zod3 = require("zod");
|
|
469
|
+
function globSelectedApiVersion(selectedApi) {
|
|
470
|
+
const at = selectedApi.indexOf("@");
|
|
471
|
+
return at === -1 ? selectedApi : selectedApi.slice(0, at) + "@*";
|
|
472
|
+
}
|
|
336
473
|
var AccessLevelSchema = import_zod3.z.enum(["read", "read_write"]);
|
|
337
474
|
var READ_HTTP_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
338
|
-
var READ_ACTION_TYPES = [
|
|
475
|
+
var READ_ACTION_TYPES = [
|
|
476
|
+
"read",
|
|
477
|
+
"read_bulk",
|
|
478
|
+
"search"
|
|
479
|
+
];
|
|
480
|
+
var READ_HTTP_METHOD_SET = new Set(READ_HTTP_METHODS);
|
|
481
|
+
var READ_ACTION_TYPE_SET = new Set(
|
|
482
|
+
READ_ACTION_TYPES
|
|
483
|
+
);
|
|
484
|
+
function isWriteRequest(context) {
|
|
485
|
+
if (context.request_type === "http_request") {
|
|
486
|
+
return !READ_HTTP_METHOD_SET.has(context.method);
|
|
487
|
+
}
|
|
488
|
+
const { action_type } = parseActionResource(context.resource);
|
|
489
|
+
return !READ_ACTION_TYPE_SET.has(action_type);
|
|
490
|
+
}
|
|
339
491
|
function buildConnectionPolicy(options) {
|
|
340
492
|
const { connectionId, selectedApi, accessLevel } = options;
|
|
341
493
|
const authStatement = {
|
|
@@ -354,7 +506,7 @@ function buildConnectionPolicy(options) {
|
|
|
354
506
|
httpConditions.push({
|
|
355
507
|
path: ["method"],
|
|
356
508
|
operator: "in",
|
|
357
|
-
value: READ_HTTP_METHODS
|
|
509
|
+
value: [...READ_HTTP_METHODS]
|
|
358
510
|
});
|
|
359
511
|
}
|
|
360
512
|
const httpStatement = {
|
|
@@ -363,19 +515,13 @@ function buildConnectionPolicy(options) {
|
|
|
363
515
|
resources: ["http"],
|
|
364
516
|
conditions: httpConditions
|
|
365
517
|
};
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
actionConditions.push({
|
|
369
|
-
path: ["action_type"],
|
|
370
|
-
operator: "in",
|
|
371
|
-
value: READ_ACTION_TYPES
|
|
372
|
-
});
|
|
373
|
-
}
|
|
518
|
+
const apiPattern = globSelectedApiVersion(selectedApi);
|
|
519
|
+
const actionResources = accessLevel === "read" ? READ_ACTION_TYPES.map((t) => `action/${apiPattern}/${t}/*`) : [`action/${apiPattern}/*/*`];
|
|
374
520
|
const actionStatement = {
|
|
375
521
|
effect: "allow",
|
|
376
522
|
permissions: ["can_execute"],
|
|
377
|
-
resources:
|
|
378
|
-
conditions:
|
|
523
|
+
resources: actionResources,
|
|
524
|
+
conditions: [connectionCondition]
|
|
379
525
|
};
|
|
380
526
|
return {
|
|
381
527
|
version: 2,
|
|
@@ -385,14 +531,17 @@ function buildConnectionPolicy(options) {
|
|
|
385
531
|
// Annotate the CommonJS export names for ESM import in node:
|
|
386
532
|
0 && (module.exports = {
|
|
387
533
|
AccessLevelSchema,
|
|
534
|
+
ActionRunContextInputSchema,
|
|
388
535
|
ActionRunContextSchema,
|
|
536
|
+
ActionTypeSchema,
|
|
389
537
|
BuildActionRunContextOptionsSchema,
|
|
390
538
|
BuildHttpRequestContextOptionsSchema,
|
|
391
539
|
DEFAULT_PORTS,
|
|
392
540
|
HttpRequestContextSchema,
|
|
393
541
|
IGNORED_HEADERS,
|
|
394
|
-
JsonValueSchema,
|
|
395
542
|
ParsedUrlSchema,
|
|
543
|
+
READ_ACTION_TYPES,
|
|
544
|
+
READ_HTTP_METHODS,
|
|
396
545
|
RequestContextSchema,
|
|
397
546
|
buildActionResource,
|
|
398
547
|
buildActionRunContext,
|
|
@@ -403,6 +552,8 @@ function buildConnectionPolicy(options) {
|
|
|
403
552
|
buildExactHttpConditions,
|
|
404
553
|
buildHttpRequestContext,
|
|
405
554
|
buildUrlString,
|
|
555
|
+
isWriteRequest,
|
|
556
|
+
parseActionResource,
|
|
406
557
|
parseUrl,
|
|
407
558
|
toExactPolicy
|
|
408
559
|
});
|