@adtl/gateway 0.1.0 → 0.2.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.
Files changed (49) hide show
  1. package/README.md +48 -4
  2. package/dist/approvals.d.ts +97 -0
  3. package/dist/approvals.d.ts.map +1 -0
  4. package/dist/approvals.js +151 -0
  5. package/dist/approvals.js.map +1 -0
  6. package/dist/audit.d.ts +10 -0
  7. package/dist/audit.d.ts.map +1 -1
  8. package/dist/audit.js.map +1 -1
  9. package/dist/cli.js +8 -2
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config.d.ts +352 -2
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +69 -2
  14. package/dist/config.js.map +1 -1
  15. package/dist/email.d.ts +35 -0
  16. package/dist/email.d.ts.map +1 -0
  17. package/dist/email.js +63 -0
  18. package/dist/email.js.map +1 -0
  19. package/dist/gateway.d.ts +12 -2
  20. package/dist/gateway.d.ts.map +1 -1
  21. package/dist/gateway.js +91 -11
  22. package/dist/gateway.js.map +1 -1
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/invoker.d.ts +10 -1
  28. package/dist/invoker.d.ts.map +1 -1
  29. package/dist/invoker.js +15 -6
  30. package/dist/invoker.js.map +1 -1
  31. package/dist/ntfy.d.ts +44 -0
  32. package/dist/ntfy.d.ts.map +1 -0
  33. package/dist/ntfy.js +133 -0
  34. package/dist/ntfy.js.map +1 -0
  35. package/dist/startup.d.ts +3 -0
  36. package/dist/startup.d.ts.map +1 -1
  37. package/dist/startup.js +39 -4
  38. package/dist/startup.js.map +1 -1
  39. package/package.json +4 -3
  40. package/src/approvals.ts +219 -0
  41. package/src/audit.ts +5 -0
  42. package/src/cli.ts +15 -4
  43. package/src/config.ts +71 -2
  44. package/src/email.ts +79 -0
  45. package/src/gateway.ts +103 -11
  46. package/src/index.ts +3 -0
  47. package/src/invoker.ts +17 -5
  48. package/src/ntfy.ts +154 -0
  49. package/src/startup.ts +36 -3
package/dist/config.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * gateway:
5
5
  * audit: ./adtl-audit.jsonl # optional JSONL audit log
6
+ * mode: audit # optional: log what would be stopped, stop nothing
6
7
  * upstreams:
7
8
  * github: # id must match `servers.github` in the label config
8
9
  * command: npx
@@ -11,9 +12,16 @@
11
12
  * docs:
12
13
  * url: https://example.com/mcp
13
14
  * headers: { Authorization: "Bearer ${DOCS_TOKEN}" }
15
+ * approvals: # optional: make "ask" really ask
16
+ * timeoutSeconds: 50
17
+ * ntfy: { topic: "${ADTL_NTFY_TOPIC}" }
18
+ * email:
19
+ * smtp: { host: smtp.example.com, port: 465, user: "${SMTP_USER}", pass: "${SMTP_PASS}" }
20
+ * from: adtl@example.com
21
+ * to: you@example.com
14
22
  *
15
- * `${VAR}` in command, args, env, cwd, url and headers is replaced from the
16
- * gateway's environment. A missing variable is a config error.
23
+ * `${VAR}` in command, args, env, cwd, url, headers and approval settings is
24
+ * replaced from the gateway's environment. A missing variable is a config error.
17
25
  */
18
26
  import { z } from "zod";
19
27
  export declare const StdioUpstreamSchema: z.ZodObject<{
@@ -70,6 +78,184 @@ export declare const UpstreamSchema: z.ZodUnion<[z.ZodObject<{
70
78
  export type StdioUpstream = z.infer<typeof StdioUpstreamSchema>;
71
79
  export type HttpUpstream = z.infer<typeof HttpUpstreamSchema>;
72
80
  export type Upstream = z.infer<typeof UpstreamSchema>;
81
+ export declare const NtfyConfigSchema: z.ZodObject<{
82
+ server: z.ZodDefault<z.ZodString>;
83
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
84
+ topic: z.ZodString;
85
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
86
+ replyTopic: z.ZodOptional<z.ZodString>;
87
+ token: z.ZodOptional<z.ZodString>;
88
+ }, "strict", z.ZodTypeAny, {
89
+ server: string;
90
+ topic: string;
91
+ replyTopic?: string | undefined;
92
+ token?: string | undefined;
93
+ }, {
94
+ topic: string;
95
+ server?: string | undefined;
96
+ replyTopic?: string | undefined;
97
+ token?: string | undefined;
98
+ }>;
99
+ export declare const EmailConfigSchema: z.ZodObject<{
100
+ smtp: z.ZodObject<{
101
+ host: z.ZodString;
102
+ port: z.ZodDefault<z.ZodNumber>;
103
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
104
+ secure: z.ZodOptional<z.ZodBoolean>;
105
+ user: z.ZodOptional<z.ZodString>;
106
+ pass: z.ZodOptional<z.ZodString>;
107
+ }, "strict", z.ZodTypeAny, {
108
+ host: string;
109
+ port: number;
110
+ secure?: boolean | undefined;
111
+ user?: string | undefined;
112
+ pass?: string | undefined;
113
+ }, {
114
+ host: string;
115
+ port?: number | undefined;
116
+ secure?: boolean | undefined;
117
+ user?: string | undefined;
118
+ pass?: string | undefined;
119
+ }>;
120
+ from: z.ZodString;
121
+ to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
122
+ on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
123
+ }, "strict", z.ZodTypeAny, {
124
+ smtp: {
125
+ host: string;
126
+ port: number;
127
+ secure?: boolean | undefined;
128
+ user?: string | undefined;
129
+ pass?: string | undefined;
130
+ };
131
+ from: string;
132
+ to: string | [string, ...string[]];
133
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
134
+ }, {
135
+ smtp: {
136
+ host: string;
137
+ port?: number | undefined;
138
+ secure?: boolean | undefined;
139
+ user?: string | undefined;
140
+ pass?: string | undefined;
141
+ };
142
+ from: string;
143
+ to: string | [string, ...string[]];
144
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
145
+ }>;
146
+ export declare const ApprovalsConfigSchema: z.ZodObject<{
147
+ /**
148
+ * How long a call waits for an answer; no answer means deny. Many MCP
149
+ * clients give up on a request after 60 seconds, hence the default.
150
+ */
151
+ timeoutSeconds: z.ZodDefault<z.ZodNumber>;
152
+ ntfy: z.ZodOptional<z.ZodObject<{
153
+ server: z.ZodDefault<z.ZodString>;
154
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
155
+ topic: z.ZodString;
156
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
157
+ replyTopic: z.ZodOptional<z.ZodString>;
158
+ token: z.ZodOptional<z.ZodString>;
159
+ }, "strict", z.ZodTypeAny, {
160
+ server: string;
161
+ topic: string;
162
+ replyTopic?: string | undefined;
163
+ token?: string | undefined;
164
+ }, {
165
+ topic: string;
166
+ server?: string | undefined;
167
+ replyTopic?: string | undefined;
168
+ token?: string | undefined;
169
+ }>>;
170
+ email: z.ZodOptional<z.ZodObject<{
171
+ smtp: z.ZodObject<{
172
+ host: z.ZodString;
173
+ port: z.ZodDefault<z.ZodNumber>;
174
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
175
+ secure: z.ZodOptional<z.ZodBoolean>;
176
+ user: z.ZodOptional<z.ZodString>;
177
+ pass: z.ZodOptional<z.ZodString>;
178
+ }, "strict", z.ZodTypeAny, {
179
+ host: string;
180
+ port: number;
181
+ secure?: boolean | undefined;
182
+ user?: string | undefined;
183
+ pass?: string | undefined;
184
+ }, {
185
+ host: string;
186
+ port?: number | undefined;
187
+ secure?: boolean | undefined;
188
+ user?: string | undefined;
189
+ pass?: string | undefined;
190
+ }>;
191
+ from: z.ZodString;
192
+ to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
193
+ on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
194
+ }, "strict", z.ZodTypeAny, {
195
+ smtp: {
196
+ host: string;
197
+ port: number;
198
+ secure?: boolean | undefined;
199
+ user?: string | undefined;
200
+ pass?: string | undefined;
201
+ };
202
+ from: string;
203
+ to: string | [string, ...string[]];
204
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
205
+ }, {
206
+ smtp: {
207
+ host: string;
208
+ port?: number | undefined;
209
+ secure?: boolean | undefined;
210
+ user?: string | undefined;
211
+ pass?: string | undefined;
212
+ };
213
+ from: string;
214
+ to: string | [string, ...string[]];
215
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
216
+ }>>;
217
+ }, "strict", z.ZodTypeAny, {
218
+ timeoutSeconds: number;
219
+ ntfy?: {
220
+ server: string;
221
+ topic: string;
222
+ replyTopic?: string | undefined;
223
+ token?: string | undefined;
224
+ } | undefined;
225
+ email?: {
226
+ smtp: {
227
+ host: string;
228
+ port: number;
229
+ secure?: boolean | undefined;
230
+ user?: string | undefined;
231
+ pass?: string | undefined;
232
+ };
233
+ from: string;
234
+ to: string | [string, ...string[]];
235
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
236
+ } | undefined;
237
+ }, {
238
+ ntfy?: {
239
+ topic: string;
240
+ server?: string | undefined;
241
+ replyTopic?: string | undefined;
242
+ token?: string | undefined;
243
+ } | undefined;
244
+ email?: {
245
+ smtp: {
246
+ host: string;
247
+ port?: number | undefined;
248
+ secure?: boolean | undefined;
249
+ user?: string | undefined;
250
+ pass?: string | undefined;
251
+ };
252
+ from: string;
253
+ to: string | [string, ...string[]];
254
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
255
+ } | undefined;
256
+ timeoutSeconds?: number | undefined;
257
+ }>;
258
+ export type ApprovalsConfig = z.infer<typeof ApprovalsConfigSchema>;
73
259
  export declare const GatewayConfigSchema: z.ZodObject<{
74
260
  upstreams: z.ZodEffects<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
75
261
  command: z.ZodString;
@@ -147,6 +333,124 @@ export declare const GatewayConfigSchema: z.ZodObject<{
147
333
  }>>;
148
334
  /** Path of a JSONL audit log. Relative paths are resolved against the config file's directory. */
149
335
  audit: z.ZodOptional<z.ZodString>;
336
+ /**
337
+ * `active` (default) enforces the policy. `audit` stops and changes nothing, and
338
+ * logs what would have been stopped: for trying a policy out safely.
339
+ */
340
+ mode: z.ZodDefault<z.ZodEnum<["active", "audit"]>>;
341
+ /** Human approvals for "ask" decisions. Without an answering channel, "ask" blocks. */
342
+ approvals: z.ZodOptional<z.ZodObject<{
343
+ /**
344
+ * How long a call waits for an answer; no answer means deny. Many MCP
345
+ * clients give up on a request after 60 seconds, hence the default.
346
+ */
347
+ timeoutSeconds: z.ZodDefault<z.ZodNumber>;
348
+ ntfy: z.ZodOptional<z.ZodObject<{
349
+ server: z.ZodDefault<z.ZodString>;
350
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
351
+ topic: z.ZodString;
352
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
353
+ replyTopic: z.ZodOptional<z.ZodString>;
354
+ token: z.ZodOptional<z.ZodString>;
355
+ }, "strict", z.ZodTypeAny, {
356
+ server: string;
357
+ topic: string;
358
+ replyTopic?: string | undefined;
359
+ token?: string | undefined;
360
+ }, {
361
+ topic: string;
362
+ server?: string | undefined;
363
+ replyTopic?: string | undefined;
364
+ token?: string | undefined;
365
+ }>>;
366
+ email: z.ZodOptional<z.ZodObject<{
367
+ smtp: z.ZodObject<{
368
+ host: z.ZodString;
369
+ port: z.ZodDefault<z.ZodNumber>;
370
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
371
+ secure: z.ZodOptional<z.ZodBoolean>;
372
+ user: z.ZodOptional<z.ZodString>;
373
+ pass: z.ZodOptional<z.ZodString>;
374
+ }, "strict", z.ZodTypeAny, {
375
+ host: string;
376
+ port: number;
377
+ secure?: boolean | undefined;
378
+ user?: string | undefined;
379
+ pass?: string | undefined;
380
+ }, {
381
+ host: string;
382
+ port?: number | undefined;
383
+ secure?: boolean | undefined;
384
+ user?: string | undefined;
385
+ pass?: string | undefined;
386
+ }>;
387
+ from: z.ZodString;
388
+ to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
389
+ on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
390
+ }, "strict", z.ZodTypeAny, {
391
+ smtp: {
392
+ host: string;
393
+ port: number;
394
+ secure?: boolean | undefined;
395
+ user?: string | undefined;
396
+ pass?: string | undefined;
397
+ };
398
+ from: string;
399
+ to: string | [string, ...string[]];
400
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
401
+ }, {
402
+ smtp: {
403
+ host: string;
404
+ port?: number | undefined;
405
+ secure?: boolean | undefined;
406
+ user?: string | undefined;
407
+ pass?: string | undefined;
408
+ };
409
+ from: string;
410
+ to: string | [string, ...string[]];
411
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
412
+ }>>;
413
+ }, "strict", z.ZodTypeAny, {
414
+ timeoutSeconds: number;
415
+ ntfy?: {
416
+ server: string;
417
+ topic: string;
418
+ replyTopic?: string | undefined;
419
+ token?: string | undefined;
420
+ } | undefined;
421
+ email?: {
422
+ smtp: {
423
+ host: string;
424
+ port: number;
425
+ secure?: boolean | undefined;
426
+ user?: string | undefined;
427
+ pass?: string | undefined;
428
+ };
429
+ from: string;
430
+ to: string | [string, ...string[]];
431
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
432
+ } | undefined;
433
+ }, {
434
+ ntfy?: {
435
+ topic: string;
436
+ server?: string | undefined;
437
+ replyTopic?: string | undefined;
438
+ token?: string | undefined;
439
+ } | undefined;
440
+ email?: {
441
+ smtp: {
442
+ host: string;
443
+ port?: number | undefined;
444
+ secure?: boolean | undefined;
445
+ user?: string | undefined;
446
+ pass?: string | undefined;
447
+ };
448
+ from: string;
449
+ to: string | [string, ...string[]];
450
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
451
+ } | undefined;
452
+ timeoutSeconds?: number | undefined;
453
+ }>>;
150
454
  /** Timeout for each interceptor invocation, in milliseconds. */
151
455
  interceptorTimeoutMs: z.ZodDefault<z.ZodNumber>;
152
456
  }, "strict", z.ZodTypeAny, {
@@ -159,6 +463,7 @@ export declare const GatewayConfigSchema: z.ZodObject<{
159
463
  url: string;
160
464
  headers: Record<string, string>;
161
465
  }>;
466
+ mode: "audit" | "active";
162
467
  interceptorTimeoutMs: number;
163
468
  interceptors?: {
164
469
  command: string;
@@ -167,6 +472,27 @@ export declare const GatewayConfigSchema: z.ZodObject<{
167
472
  cwd?: string | undefined;
168
473
  } | undefined;
169
474
  audit?: string | undefined;
475
+ approvals?: {
476
+ timeoutSeconds: number;
477
+ ntfy?: {
478
+ server: string;
479
+ topic: string;
480
+ replyTopic?: string | undefined;
481
+ token?: string | undefined;
482
+ } | undefined;
483
+ email?: {
484
+ smtp: {
485
+ host: string;
486
+ port: number;
487
+ secure?: boolean | undefined;
488
+ user?: string | undefined;
489
+ pass?: string | undefined;
490
+ };
491
+ from: string;
492
+ to: string | [string, ...string[]];
493
+ on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
494
+ } | undefined;
495
+ } | undefined;
170
496
  }, {
171
497
  upstreams: Record<string, {
172
498
  command: string;
@@ -184,6 +510,28 @@ export declare const GatewayConfigSchema: z.ZodObject<{
184
510
  cwd?: string | undefined;
185
511
  } | undefined;
186
512
  audit?: string | undefined;
513
+ mode?: "audit" | "active" | undefined;
514
+ approvals?: {
515
+ ntfy?: {
516
+ topic: string;
517
+ server?: string | undefined;
518
+ replyTopic?: string | undefined;
519
+ token?: string | undefined;
520
+ } | undefined;
521
+ email?: {
522
+ smtp: {
523
+ host: string;
524
+ port?: number | undefined;
525
+ secure?: boolean | undefined;
526
+ user?: string | undefined;
527
+ pass?: string | undefined;
528
+ };
529
+ from: string;
530
+ to: string | [string, ...string[]];
531
+ on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
532
+ } | undefined;
533
+ timeoutSeconds?: number | undefined;
534
+ } | undefined;
187
535
  interceptorTimeoutMs?: number | undefined;
188
536
  }>;
189
537
  export type GatewayConfig = z.infer<typeof GatewayConfigSchema>;
@@ -195,5 +543,7 @@ export declare class EnvExpansionError extends Error {
195
543
  /** Replace `${VAR}` with values from `env`. `$${VAR}` keeps a literal `${VAR}`. */
196
544
  export declare function expandEnv(value: string, env: NodeJS.ProcessEnv, where: string): string;
197
545
  export declare function expandUpstream<T extends Upstream>(id: string, u: T, env: NodeJS.ProcessEnv): T;
546
+ /** Expand `${VAR}` in every string of the approvals section. */
547
+ export declare function expandApprovals(a: ApprovalsConfig, env: NodeJS.ProcessEnv): ApprovalsConfig;
198
548
  export declare function isHttpUpstream(u: Upstream): u is HttpUpstream;
199
549
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAOrB,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;EAKpB,CAAC;AAEZ,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAqD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ5B,8GAA8G;;;;;;;;;;;;;;;;;IAE9G,kGAAkG;;IAElG,gEAAgE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzD,CAAC;AACZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAIrD;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtF;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAY9F;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,YAAY,CAE7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAOrB,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;EAKpB,CAAC;AAEZ,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAqD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,gBAAgB;;IAGzB,+FAA+F;;IAE/F,6DAA6D;;;;;;;;;;;;;EAItD,CAAC;AAEZ,eAAO,MAAM,iBAAiB;;;;QAMtB,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUtE,CAAC;AAEZ,eAAO,MAAM,qBAAqB;IAE9B;;;OAGG;;;;QA/BH,+FAA+F;;QAE/F,6DAA6D;;;;;;;;;;;;;;;;;;YAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtE,CAAC;AACZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ5B,8GAA8G;;;;;;;;;;;;;;;;;IAE9G,kGAAkG;;IAElG;;;OAGG;;IAEH,uFAAuF;;QA5BvF;;;WAGG;;;;YA/BH,+FAA+F;;YAE/F,6DAA6D;;;;;;;;;;;;;;;;;;gBAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4C7E,gEAAgE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzD,CAAC;AACZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAIrD;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtF;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAY9F;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAQ3F;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,YAAY,CAE7D"}
package/dist/config.js CHANGED
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * gateway:
5
5
  * audit: ./adtl-audit.jsonl # optional JSONL audit log
6
+ * mode: audit # optional: log what would be stopped, stop nothing
6
7
  * upstreams:
7
8
  * github: # id must match `servers.github` in the label config
8
9
  * command: npx
@@ -11,11 +12,19 @@
11
12
  * docs:
12
13
  * url: https://example.com/mcp
13
14
  * headers: { Authorization: "Bearer ${DOCS_TOKEN}" }
15
+ * approvals: # optional: make "ask" really ask
16
+ * timeoutSeconds: 50
17
+ * ntfy: { topic: "${ADTL_NTFY_TOPIC}" }
18
+ * email:
19
+ * smtp: { host: smtp.example.com, port: 465, user: "${SMTP_USER}", pass: "${SMTP_PASS}" }
20
+ * from: adtl@example.com
21
+ * to: you@example.com
14
22
  *
15
- * `${VAR}` in command, args, env, cwd, url and headers is replaced from the
16
- * gateway's environment. A missing variable is a config error.
23
+ * `${VAR}` in command, args, env, cwd, url, headers and approval settings is
24
+ * replaced from the gateway's environment. A missing variable is a config error.
17
25
  */
18
26
  import { z } from "zod";
27
+ import { EMAIL_EVENTS } from "./email.js";
19
28
  const UPSTREAM_ID = /^[A-Za-z0-9-]+$/;
20
29
  export const StdioUpstreamSchema = z
21
30
  .object({
@@ -32,6 +41,44 @@ export const HttpUpstreamSchema = z
32
41
  })
33
42
  .strict();
34
43
  export const UpstreamSchema = z.union([StdioUpstreamSchema, HttpUpstreamSchema]);
44
+ export const NtfyConfigSchema = z
45
+ .object({
46
+ server: z.string().min(1).default("https://ntfy.sh"),
47
+ /** Topic approval requests are sent to. Anyone who can read it can approve: keep it secret. */
48
+ topic: z.string().min(1),
49
+ /** Topic answers are posted to. Default: `<topic>-reply`. */
50
+ replyTopic: z.string().min(1).optional(),
51
+ token: z.string().min(1).optional(),
52
+ })
53
+ .strict();
54
+ export const EmailConfigSchema = z
55
+ .object({
56
+ smtp: z
57
+ .object({
58
+ host: z.string().min(1),
59
+ port: z.number().int().positive().default(587),
60
+ /** TLS from the start. Default: true on port 465, otherwise STARTTLS. */
61
+ secure: z.boolean().optional(),
62
+ user: z.string().min(1).optional(),
63
+ pass: z.string().optional(),
64
+ })
65
+ .strict(),
66
+ from: z.string().min(1),
67
+ to: z.union([z.string().min(1), z.array(z.string().min(1)).nonempty()]),
68
+ on: z.array(z.enum(EMAIL_EVENTS)).nonempty().default(["pending", "blocked"]),
69
+ })
70
+ .strict();
71
+ export const ApprovalsConfigSchema = z
72
+ .object({
73
+ /**
74
+ * How long a call waits for an answer; no answer means deny. Many MCP
75
+ * clients give up on a request after 60 seconds, hence the default.
76
+ */
77
+ timeoutSeconds: z.number().int().positive().max(3600).default(50),
78
+ ntfy: NtfyConfigSchema.optional(),
79
+ email: EmailConfigSchema.optional(),
80
+ })
81
+ .strict();
35
82
  export const GatewayConfigSchema = z
36
83
  .object({
37
84
  upstreams: z
@@ -44,6 +91,13 @@ export const GatewayConfigSchema = z
44
91
  interceptors: StdioUpstreamSchema.optional(),
45
92
  /** Path of a JSONL audit log. Relative paths are resolved against the config file's directory. */
46
93
  audit: z.string().min(1).optional(),
94
+ /**
95
+ * `active` (default) enforces the policy. `audit` stops and changes nothing, and
96
+ * logs what would have been stopped: for trying a policy out safely.
97
+ */
98
+ mode: z.enum(["active", "audit"]).default("active"),
99
+ /** Human approvals for "ask" decisions. Without an answering channel, "ask" blocks. */
100
+ approvals: ApprovalsConfigSchema.optional(),
47
101
  /** Timeout for each interceptor invocation, in milliseconds. */
48
102
  interceptorTimeoutMs: z.number().int().positive().default(5000),
49
103
  })
@@ -84,6 +138,19 @@ export function expandUpstream(id, u, env) {
84
138
  ...(u.cwd !== undefined ? { cwd: expandEnv(u.cwd, env, `${where}.cwd`) } : {}),
85
139
  };
86
140
  }
141
+ /** Expand `${VAR}` in every string of the approvals section. */
142
+ export function expandApprovals(a, env) {
143
+ const walk = (v, where) => {
144
+ if (typeof v === "string")
145
+ return expandEnv(v, env, where);
146
+ if (Array.isArray(v))
147
+ return v.map((x, i) => walk(x, `${where}[${i}]`));
148
+ if (v && typeof v === "object")
149
+ return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x, `${where}.${k}`)]));
150
+ return v;
151
+ };
152
+ return walk(a, "gateway.approvals");
153
+ }
87
154
  export function isHttpUpstream(u) {
88
155
  return "url" in u;
89
156
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAEtC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC3B,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC1C,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAKjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;IACpD,+FAA+F;IAC/F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,6DAA6D;IAC7D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CACpC,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,CAAC;IACN,IAAI,EAAE,CAAC;SACJ,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;QAC9C,yEAAyE;QACzE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC5B,CAAC;SACD,MAAM,EAAE;IACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;CAC7E,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,MAAM,CAAC;IACN;;;OAGG;IACH,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACjE,IAAI,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IACjC,KAAK,EAAE,iBAAiB,CAAC,QAAQ,EAAE;CACpC,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,CAAC;IACN,SAAS,EAAE,CAAC;SACT,MAAM,CAAC,cAAc,CAAC;SACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,0CAA0C,CAAC;SACpF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE;QACjE,OAAO,EAAE,gGAAgG;KAC1G,CAAC;IACJ,8GAA8G;IAC9G,YAAY,EAAE,mBAAmB,CAAC,QAAQ,EAAE;IAC5C,kGAAkG;IAClG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACnC;;;OAGG;IACH,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACnD,uFAAuF;IACvF,SAAS,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IAC3C,gEAAgE;IAChE,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CAChE,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACrB;IAArB,YAAqB,QAAgB,EAAE,KAAa;QAClD,KAAK,CAAC,wBAAwB,QAAQ,wBAAwB,KAAK,GAAG,CAAC,CAAC;QADrD,aAAQ,GAAR,QAAQ,CAAQ;QAEnC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,mFAAmF;AACnF,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,GAAsB,EAAE,KAAa;IAC5E,OAAO,KAAK,CAAC,OAAO,CAAC,sCAAsC,EAAE,CAAC,KAAK,EAAE,MAAc,EAAE,IAAY,EAAE,EAAE;QACnG,IAAI,MAAM;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,SAAS;YAAE,MAAM,IAAI,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9D,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,GAA2B,EAAE,GAAsB,EAAE,KAAa;IACtF,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1G,CAAC;AAED,MAAM,UAAU,cAAc,CAAqB,EAAU,EAAE,CAAI,EAAE,GAAsB;IACzF,MAAM,KAAK,GAAG,qBAAqB,EAAE,EAAE,CAAC;IACxC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,UAAU,CAAC,EAAE,CAAC;IACzH,CAAC;IACD,OAAO;QACL,GAAG,CAAC;QACJ,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,UAAU,CAAC;QACtD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,CAAC,CAAC;QACpE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;QAC7C,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,eAAe,CAAC,CAAkB,EAAE,GAAsB;IACxE,MAAM,IAAI,GAAG,CAAC,CAAU,EAAE,KAAa,EAAW,EAAE;QAClD,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5H,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IACF,OAAO,IAAI,CAAC,CAAC,EAAE,mBAAmB,CAAoB,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,CAAW;IACxC,OAAO,KAAK,IAAI,CAAC,CAAC;AACpB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { ApprovalEvent, Notifier } from "./approvals.js";
2
+ export declare const EMAIL_EVENTS: readonly ["pending", "blocked", "approved", "denied", "timeout", "undeliverable"];
3
+ export type EmailEvent = (typeof EMAIL_EVENTS)[number];
4
+ export interface MailSender {
5
+ sendMail(mail: {
6
+ from: string;
7
+ to: string[];
8
+ subject: string;
9
+ text: string;
10
+ }): Promise<unknown>;
11
+ }
12
+ export interface EmailOptions {
13
+ from: string;
14
+ to: string[];
15
+ /** Which events send an email. */
16
+ on: EmailEvent[];
17
+ /** SMTP settings, used unless `sender` is given. */
18
+ smtp?: {
19
+ host: string;
20
+ port: number;
21
+ secure?: boolean;
22
+ user?: string;
23
+ pass?: string;
24
+ };
25
+ sender?: MailSender;
26
+ }
27
+ export declare class EmailNotifier implements Notifier {
28
+ private readonly opts;
29
+ readonly name = "email";
30
+ private readonly sender;
31
+ constructor(opts: EmailOptions);
32
+ notify(event: ApprovalEvent): Promise<void>;
33
+ private compose;
34
+ }
35
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE9D,eAAO,MAAM,YAAY,mFAAoF,CAAC;AAC9G,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjG;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,kCAAkC;IAClC,EAAE,EAAE,UAAU,EAAE,CAAC;IACjB,oDAAoD;IACpD,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,qBAAa,aAAc,YAAW,QAAQ;IAIhC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;gBAEP,IAAI,EAAE,YAAY;IAgBzC,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,OAAO,CAAC,OAAO;CAwBhB"}
package/dist/email.js ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Email notices over SMTP. Notify only, on purpose: emails never contain
3
+ * approve links, because mail security scanners open links automatically and
4
+ * would approve calls by themselves. Approving happens on the push channel.
5
+ *
6
+ * Emails name the tool, server and reason, never arguments or results.
7
+ */
8
+ import nodemailer from "nodemailer";
9
+ export const EMAIL_EVENTS = ["pending", "blocked", "approved", "denied", "timeout", "undeliverable"];
10
+ export class EmailNotifier {
11
+ opts;
12
+ name = "email";
13
+ sender;
14
+ constructor(opts) {
15
+ this.opts = opts;
16
+ if (opts.sender) {
17
+ this.sender = opts.sender;
18
+ }
19
+ else if (opts.smtp) {
20
+ const { host, port, secure, user, pass } = opts.smtp;
21
+ this.sender = nodemailer.createTransport({
22
+ host,
23
+ port,
24
+ secure: secure ?? port === 465,
25
+ ...(user !== undefined ? { auth: { user, pass } } : {}),
26
+ });
27
+ }
28
+ else {
29
+ throw new Error("EmailNotifier needs smtp settings or a sender");
30
+ }
31
+ }
32
+ async notify(event) {
33
+ const kind = event.kind === "resolved" ? event.result.outcome : event.kind;
34
+ if (!this.opts.on.includes(kind))
35
+ return;
36
+ const { subject, text } = this.compose(event);
37
+ await this.sender.sendMail({ from: this.opts.from, to: this.opts.to, subject, text });
38
+ }
39
+ compose(event) {
40
+ const footer = "\n\n-- \nSent by ADTL (adtl-gateway). This email never contains approve links; approve on your push channel.";
41
+ if (event.kind === "blocked") {
42
+ return {
43
+ subject: `ADTL blocked ${event.server}.${event.tool}`,
44
+ text: `ADTL blocked a call to ${event.server}.${event.tool}.\n\nReason: ${event.reason}\nRule: ${event.matched.join(", ") || "default"}\nSession: ${event.sessionId}${footer}`,
45
+ };
46
+ }
47
+ const r = event.request;
48
+ const subject = `${r.server}.${r.tool}`;
49
+ if (event.kind === "pending") {
50
+ return {
51
+ subject: `ADTL: approval needed for ${subject}`,
52
+ text: `An agent wants to call ${subject} and ADTL needs your approval.\n\nReason: ${r.reason}\nRule: ${r.matched.join(", ") || "default"}\n` +
53
+ `Session: ${r.sessionId}\nExpires: ${r.expiresAt.toISOString()} (no answer means deny)${footer}`,
54
+ };
55
+ }
56
+ const res = event.result;
57
+ return {
58
+ subject: `ADTL: ${subject} ${res.outcome}`,
59
+ text: `The approval request for ${subject} was ${res.outcome}${res.channel ? ` via ${res.channel}` : ""} after ${Math.round(res.waitedMs / 1000)}s.\n\nReason it was asked: ${r.reason}\nSession: ${r.sessionId}${footer}`,
60
+ };
61
+ }
62
+ }
63
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"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"}