@zapier/policy-context 0.9.0 → 1.0.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 +262 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +163 -37
- package/dist/index.d.ts +163 -37
- package/dist/index.js +256 -111
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -22,13 +22,16 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AccessLevelSchema: () => AccessLevelSchema,
|
|
24
24
|
ActionRunContextSchema: () => ActionRunContextSchema,
|
|
25
|
+
ActionTypeSchema: () => ActionTypeSchema,
|
|
25
26
|
BuildActionRunContextOptionsSchema: () => BuildActionRunContextOptionsSchema,
|
|
26
27
|
BuildHttpRequestContextOptionsSchema: () => BuildHttpRequestContextOptionsSchema,
|
|
27
28
|
DEFAULT_PORTS: () => DEFAULT_PORTS,
|
|
28
29
|
HttpRequestContextSchema: () => HttpRequestContextSchema,
|
|
29
30
|
IGNORED_HEADERS: () => IGNORED_HEADERS,
|
|
30
|
-
JsonValueSchema: () => JsonValueSchema,
|
|
31
|
+
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,14 +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
|
+
var import_policy_schema = require("@zapier/policy-schema");
|
|
56
|
+
(0, import_zod_to_openapi.extendZodWithOpenApi)(import_zod.z);
|
|
50
57
|
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
|
-
|
|
56
|
-
})
|
|
58
|
+
scheme: import_zod.z.string().openapi({ description: 'URL scheme, e.g. "https"' }),
|
|
59
|
+
host: import_zod.z.string().openapi({ description: 'Hostname, e.g. "api.example.com"' }),
|
|
60
|
+
port: import_zod.z.number().int().openapi({
|
|
61
|
+
description: "Port number (defaults to 443 for https, 80 for http)"
|
|
62
|
+
}),
|
|
63
|
+
path: import_zod.z.string().openapi({ description: 'URL path, e.g. "/v1/foo"' }),
|
|
64
|
+
query: import_zod.z.record(import_zod.z.string(), import_zod.z.array(import_zod.z.string())).openapi({
|
|
65
|
+
description: "Query parameters as key to string array mapping"
|
|
66
|
+
})
|
|
67
|
+
}).openapi("ParsedUrl");
|
|
57
68
|
var DEFAULT_PORTS = {
|
|
58
69
|
http: 80,
|
|
59
70
|
https: 443
|
|
@@ -88,33 +99,136 @@ function buildUrlString(parsed) {
|
|
|
88
99
|
}
|
|
89
100
|
var HttpRequestContextSchema = import_zod.z.object({
|
|
90
101
|
request_type: import_zod.z.literal("http_request"),
|
|
91
|
-
method: import_zod.z.string(),
|
|
102
|
+
method: import_zod.z.string().max(10).transform((m) => m.toUpperCase()),
|
|
92
103
|
/** Parsed URL components for policy condition matching */
|
|
93
104
|
url: ParsedUrlSchema,
|
|
94
105
|
/** Filtered headers (IGNORED_HEADERS excluded, keys lowercased) */
|
|
95
|
-
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string())
|
|
106
|
+
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).openapi({
|
|
107
|
+
description: "Filtered headers (IGNORED_HEADERS excluded, keys lowercased)"
|
|
108
|
+
}),
|
|
96
109
|
/** Raw body string */
|
|
97
|
-
body: import_zod.z.string().nullable(),
|
|
110
|
+
body: import_zod.z.string().max(65536).nullable(),
|
|
98
111
|
/** Parsed JSON body */
|
|
99
|
-
body_json: JsonValueSchema.nullable()
|
|
112
|
+
body_json: import_policy_schema.JsonValueSchema.nullable().openapi({
|
|
113
|
+
// `type: 'object'` is a placeholder so zod-to-openapi short-circuits
|
|
114
|
+
// introspection of the recursive JsonValueSchema (z.lazy). The
|
|
115
|
+
// generator script strips this `type` after emit so the produced
|
|
116
|
+
// schema matches the original "any JSON value" shape.
|
|
117
|
+
type: "object",
|
|
118
|
+
description: "Parsed JSON body (if applicable)"
|
|
119
|
+
}),
|
|
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()
|
|
104
|
-
});
|
|
105
|
-
var
|
|
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({
|
|
106
170
|
request_type: import_zod.z.literal("action_run"),
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
+
inputs: import_policy_schema.JsonValueSchema.optional().openapi({
|
|
188
|
+
// `type: 'object'` is a placeholder so zod-to-openapi short-circuits
|
|
189
|
+
// introspection of the recursive JsonValueSchema (z.lazy). The
|
|
190
|
+
// generator script strips this `type` after emit so the produced
|
|
191
|
+
// schema matches the original "any inputs" shape.
|
|
192
|
+
type: "object",
|
|
193
|
+
description: "Action input parameters"
|
|
194
|
+
}),
|
|
195
|
+
reason: import_zod.z.string().max(1024).optional().openapi({ description: "Optional human-readable reason for the request" })
|
|
196
|
+
}).openapi("ActionRunContext", {
|
|
197
|
+
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."
|
|
198
|
+
});
|
|
199
|
+
var ActionRunContextSchema = ActionRunContextInputSchema.transform(
|
|
200
|
+
(input, ctx) => {
|
|
201
|
+
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);
|
|
202
|
+
if (resource === void 0) {
|
|
203
|
+
ctx.addIssue({
|
|
204
|
+
code: "custom",
|
|
205
|
+
message: "action_run context requires either `resource` or all of `selected_api`/`action_type`/`action_key`"
|
|
206
|
+
});
|
|
207
|
+
return import_zod.z.NEVER;
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
parseActionResource(resource);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
ctx.addIssue({
|
|
213
|
+
code: "custom",
|
|
214
|
+
message: err instanceof Error ? err.message : String(err)
|
|
215
|
+
});
|
|
216
|
+
return import_zod.z.NEVER;
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
request_type: "action_run",
|
|
220
|
+
resource,
|
|
221
|
+
...input.connection_id !== void 0 && {
|
|
222
|
+
connection_id: input.connection_id
|
|
223
|
+
},
|
|
224
|
+
...input.inputs !== void 0 && { inputs: input.inputs },
|
|
225
|
+
...input.reason !== void 0 && { reason: input.reason }
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
var RequestContextSchema = import_zod.z.union([HttpRequestContextSchema, ActionRunContextSchema]).openapi("RequestContext", {
|
|
230
|
+
description: "Discriminated union over request_type."
|
|
113
231
|
});
|
|
114
|
-
var RequestContextSchema = import_zod.z.discriminatedUnion("request_type", [
|
|
115
|
-
HttpRequestContextSchema,
|
|
116
|
-
ActionRunContextSchema
|
|
117
|
-
]);
|
|
118
232
|
|
|
119
233
|
// src/constants.ts
|
|
120
234
|
var IGNORED_HEADERS = /* @__PURE__ */ new Set([
|
|
@@ -148,74 +262,6 @@ var IGNORED_HEADERS = /* @__PURE__ */ new Set([
|
|
|
148
262
|
|
|
149
263
|
// src/builders.ts
|
|
150
264
|
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: 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: 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
265
|
|
|
220
266
|
// src/conditions.ts
|
|
221
267
|
function buildExactHttpConditions(context) {
|
|
@@ -244,6 +290,12 @@ function buildExactHttpConditions(context) {
|
|
|
244
290
|
operator: "equals",
|
|
245
291
|
value: context.body_json
|
|
246
292
|
});
|
|
293
|
+
} else if (context.body !== null) {
|
|
294
|
+
conditions.push({
|
|
295
|
+
path: ["body"],
|
|
296
|
+
operator: "equals",
|
|
297
|
+
value: context.body
|
|
298
|
+
});
|
|
247
299
|
}
|
|
248
300
|
for (const [key, value] of Object.entries(context.headers)) {
|
|
249
301
|
if (!IGNORED_HEADERS.has(key.toLowerCase()) && typeof value === "string") {
|
|
@@ -267,7 +319,7 @@ function buildDomainHttpConditions(context) {
|
|
|
267
319
|
}
|
|
268
320
|
function buildExactActionConditions(context) {
|
|
269
321
|
const conditions = [];
|
|
270
|
-
if (context.inputs !== void 0 && context.inputs !== null
|
|
322
|
+
if (context.inputs !== void 0 && context.inputs !== null) {
|
|
271
323
|
conditions.push({
|
|
272
324
|
path: ["inputs"],
|
|
273
325
|
operator: "equals",
|
|
@@ -276,11 +328,91 @@ function buildExactActionConditions(context) {
|
|
|
276
328
|
}
|
|
277
329
|
return conditions;
|
|
278
330
|
}
|
|
279
|
-
function buildActionResource(
|
|
280
|
-
return `action/${
|
|
331
|
+
function buildActionResource(parts) {
|
|
332
|
+
return `action/${parts.selected_api}/${parts.action_type}/${parts.action_key}`;
|
|
281
333
|
}
|
|
282
|
-
function buildBroadActionResource(
|
|
283
|
-
return `action/${
|
|
334
|
+
function buildBroadActionResource(parts) {
|
|
335
|
+
return `action/${parts.selected_api}/${parts.action_type}/*`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/builders.ts
|
|
339
|
+
var BuildHttpRequestContextOptionsSchema = import_zod2.z.object({
|
|
340
|
+
method: import_zod2.z.string(),
|
|
341
|
+
/** Raw URL string. Will be normalized with https:// if no protocol present. */
|
|
342
|
+
url: import_zod2.z.string(),
|
|
343
|
+
/** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */
|
|
344
|
+
headers: import_zod2.z.record(
|
|
345
|
+
import_zod2.z.string(),
|
|
346
|
+
import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.string()), import_zod2.z.undefined()])
|
|
347
|
+
).optional(),
|
|
348
|
+
/** Raw body string */
|
|
349
|
+
body: import_zod2.z.string().nullable().optional(),
|
|
350
|
+
/** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */
|
|
351
|
+
body_json: import_policy_schema.JsonValueSchema.optional(),
|
|
352
|
+
/** Connection ID associated with this request */
|
|
353
|
+
connection_id: import_zod2.z.string().optional()
|
|
354
|
+
});
|
|
355
|
+
function buildHttpRequestContext(options) {
|
|
356
|
+
const parsed = BuildHttpRequestContextOptionsSchema.parse(options);
|
|
357
|
+
const rawUrl = parsed.url.includes("://") ? parsed.url : `https://${parsed.url}`;
|
|
358
|
+
const url = parseUrl(rawUrl);
|
|
359
|
+
const headers = {};
|
|
360
|
+
if (parsed.headers) {
|
|
361
|
+
for (const [key, value] of Object.entries(parsed.headers)) {
|
|
362
|
+
const lowerKey = key.toLowerCase();
|
|
363
|
+
if (!IGNORED_HEADERS.has(lowerKey) && typeof value === "string") {
|
|
364
|
+
headers[lowerKey] = value;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
let body_json = null;
|
|
369
|
+
if (parsed.body_json !== void 0) {
|
|
370
|
+
body_json = parsed.body_json;
|
|
371
|
+
} else if (parsed.body) {
|
|
372
|
+
const contentType = headers["content-type"];
|
|
373
|
+
const isJson = typeof contentType === "string" && (contentType.includes("application/json") || contentType.includes("application/") && contentType.includes("+json"));
|
|
374
|
+
if (isJson) {
|
|
375
|
+
try {
|
|
376
|
+
body_json = JSON.parse(parsed.body);
|
|
377
|
+
} catch {
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return HttpRequestContextSchema.parse({
|
|
382
|
+
request_type: "http_request",
|
|
383
|
+
method: parsed.method.toUpperCase(),
|
|
384
|
+
url,
|
|
385
|
+
headers,
|
|
386
|
+
body: parsed.body ?? null,
|
|
387
|
+
body_json,
|
|
388
|
+
connection_id: parsed.connection_id
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
var BuildActionRunContextOptionsSchema = import_zod2.z.object({
|
|
392
|
+
selected_api: import_zod2.z.string().regex(ACTION_RESOURCE_SEGMENT_PATTERN, {
|
|
393
|
+
message: "selected_api must contain only [A-Za-z0-9._@+-] (no globs, slashes, or whitespace)"
|
|
394
|
+
}),
|
|
395
|
+
action_type: ActionTypeSchema,
|
|
396
|
+
action_key: import_zod2.z.string().regex(ACTION_RESOURCE_SEGMENT_PATTERN, {
|
|
397
|
+
message: "action_key must contain only [A-Za-z0-9._@+-] (no globs, slashes, or whitespace)"
|
|
398
|
+
}),
|
|
399
|
+
connection_id: import_zod2.z.string().optional(),
|
|
400
|
+
inputs: import_policy_schema.JsonValueSchema.optional(),
|
|
401
|
+
reason: import_zod2.z.string().optional()
|
|
402
|
+
});
|
|
403
|
+
function buildActionRunContext(options) {
|
|
404
|
+
const parsed = BuildActionRunContextOptionsSchema.parse(options);
|
|
405
|
+
return ActionRunContextSchema.parse({
|
|
406
|
+
request_type: "action_run",
|
|
407
|
+
resource: buildActionResource({
|
|
408
|
+
selected_api: parsed.selected_api,
|
|
409
|
+
action_type: parsed.action_type,
|
|
410
|
+
action_key: parsed.action_key
|
|
411
|
+
}),
|
|
412
|
+
connection_id: parsed.connection_id,
|
|
413
|
+
inputs: parsed.inputs,
|
|
414
|
+
reason: parsed.reason
|
|
415
|
+
});
|
|
284
416
|
}
|
|
285
417
|
|
|
286
418
|
// src/policies.ts
|
|
@@ -319,7 +451,7 @@ function actionContextToPolicy(context) {
|
|
|
319
451
|
statements.push({
|
|
320
452
|
effect: "allow",
|
|
321
453
|
permissions: ["can_execute"],
|
|
322
|
-
resources: [
|
|
454
|
+
resources: [context.resource],
|
|
323
455
|
conditions: buildExactActionConditions(context)
|
|
324
456
|
});
|
|
325
457
|
return { version: 2, statements };
|
|
@@ -333,9 +465,28 @@ function toExactPolicy(context) {
|
|
|
333
465
|
|
|
334
466
|
// src/connection-policy.ts
|
|
335
467
|
var import_zod3 = require("zod");
|
|
468
|
+
function globSelectedApiVersion(selectedApi) {
|
|
469
|
+
const at = selectedApi.indexOf("@");
|
|
470
|
+
return at === -1 ? selectedApi : selectedApi.slice(0, at) + "@*";
|
|
471
|
+
}
|
|
336
472
|
var AccessLevelSchema = import_zod3.z.enum(["read", "read_write"]);
|
|
337
473
|
var READ_HTTP_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
338
|
-
var READ_ACTION_TYPES = [
|
|
474
|
+
var READ_ACTION_TYPES = [
|
|
475
|
+
"read",
|
|
476
|
+
"read_bulk",
|
|
477
|
+
"search"
|
|
478
|
+
];
|
|
479
|
+
var READ_HTTP_METHOD_SET = new Set(READ_HTTP_METHODS);
|
|
480
|
+
var READ_ACTION_TYPE_SET = new Set(
|
|
481
|
+
READ_ACTION_TYPES
|
|
482
|
+
);
|
|
483
|
+
function isWriteRequest(context) {
|
|
484
|
+
if (context.request_type === "http_request") {
|
|
485
|
+
return !READ_HTTP_METHOD_SET.has(context.method);
|
|
486
|
+
}
|
|
487
|
+
const { action_type } = parseActionResource(context.resource);
|
|
488
|
+
return !READ_ACTION_TYPE_SET.has(action_type);
|
|
489
|
+
}
|
|
339
490
|
function buildConnectionPolicy(options) {
|
|
340
491
|
const { connectionId, selectedApi, accessLevel } = options;
|
|
341
492
|
const authStatement = {
|
|
@@ -354,7 +505,7 @@ function buildConnectionPolicy(options) {
|
|
|
354
505
|
httpConditions.push({
|
|
355
506
|
path: ["method"],
|
|
356
507
|
operator: "in",
|
|
357
|
-
value: READ_HTTP_METHODS
|
|
508
|
+
value: [...READ_HTTP_METHODS]
|
|
358
509
|
});
|
|
359
510
|
}
|
|
360
511
|
const httpStatement = {
|
|
@@ -363,19 +514,13 @@ function buildConnectionPolicy(options) {
|
|
|
363
514
|
resources: ["http"],
|
|
364
515
|
conditions: httpConditions
|
|
365
516
|
};
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
actionConditions.push({
|
|
369
|
-
path: ["action_type"],
|
|
370
|
-
operator: "in",
|
|
371
|
-
value: READ_ACTION_TYPES
|
|
372
|
-
});
|
|
373
|
-
}
|
|
517
|
+
const apiPattern = globSelectedApiVersion(selectedApi);
|
|
518
|
+
const actionResources = accessLevel === "read" ? READ_ACTION_TYPES.map((t) => `action/${apiPattern}/${t}/*`) : [`action/${apiPattern}/*/*`];
|
|
374
519
|
const actionStatement = {
|
|
375
520
|
effect: "allow",
|
|
376
521
|
permissions: ["can_execute"],
|
|
377
|
-
resources:
|
|
378
|
-
conditions:
|
|
522
|
+
resources: actionResources,
|
|
523
|
+
conditions: [connectionCondition]
|
|
379
524
|
};
|
|
380
525
|
return {
|
|
381
526
|
version: 2,
|
|
@@ -386,6 +531,7 @@ function buildConnectionPolicy(options) {
|
|
|
386
531
|
0 && (module.exports = {
|
|
387
532
|
AccessLevelSchema,
|
|
388
533
|
ActionRunContextSchema,
|
|
534
|
+
ActionTypeSchema,
|
|
389
535
|
BuildActionRunContextOptionsSchema,
|
|
390
536
|
BuildHttpRequestContextOptionsSchema,
|
|
391
537
|
DEFAULT_PORTS,
|
|
@@ -393,6 +539,8 @@ function buildConnectionPolicy(options) {
|
|
|
393
539
|
IGNORED_HEADERS,
|
|
394
540
|
JsonValueSchema,
|
|
395
541
|
ParsedUrlSchema,
|
|
542
|
+
READ_ACTION_TYPES,
|
|
543
|
+
READ_HTTP_METHODS,
|
|
396
544
|
RequestContextSchema,
|
|
397
545
|
buildActionResource,
|
|
398
546
|
buildActionRunContext,
|
|
@@ -403,6 +551,8 @@ function buildConnectionPolicy(options) {
|
|
|
403
551
|
buildExactHttpConditions,
|
|
404
552
|
buildHttpRequestContext,
|
|
405
553
|
buildUrlString,
|
|
554
|
+
isWriteRequest,
|
|
555
|
+
parseActionResource,
|
|
406
556
|
parseUrl,
|
|
407
557
|
toExactPolicy
|
|
408
558
|
});
|