airlock-bot 0.2.19 → 0.2.21

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 (74) hide show
  1. package/README.md +162 -24
  2. package/dist/backend/cli/adapter.d.ts.map +1 -1
  3. package/dist/backend/cli/adapter.js +7 -1
  4. package/dist/backend/cli/adapter.js.map +1 -1
  5. package/dist/backend/exec-adapter.d.ts.map +1 -1
  6. package/dist/backend/exec-adapter.js +2 -1
  7. package/dist/backend/exec-adapter.js.map +1 -1
  8. package/dist/backend/factory.d.ts.map +1 -1
  9. package/dist/backend/factory.js +3 -2
  10. package/dist/backend/factory.js.map +1 -1
  11. package/dist/backend/mcp-adapter.d.ts +7 -1
  12. package/dist/backend/mcp-adapter.d.ts.map +1 -1
  13. package/dist/backend/mcp-adapter.js +49 -1
  14. package/dist/backend/mcp-adapter.js.map +1 -1
  15. package/dist/config/loader.d.ts.map +1 -1
  16. package/dist/config/loader.js +23 -0
  17. package/dist/config/loader.js.map +1 -1
  18. package/dist/config/schema.d.ts +1518 -16
  19. package/dist/config/schema.d.ts.map +1 -1
  20. package/dist/config/schema.js +151 -3
  21. package/dist/config/schema.js.map +1 -1
  22. package/dist/gateway.d.ts.map +1 -1
  23. package/dist/gateway.js +5 -0
  24. package/dist/gateway.js.map +1 -1
  25. package/dist/hitl/engine.d.ts +2 -0
  26. package/dist/hitl/engine.d.ts.map +1 -1
  27. package/dist/hitl/engine.js +2 -0
  28. package/dist/hitl/engine.js.map +1 -1
  29. package/dist/hitl/formatter.d.ts.map +1 -1
  30. package/dist/hitl/formatter.js +17 -1
  31. package/dist/hitl/formatter.js.map +1 -1
  32. package/dist/hitl/providers/tui.d.ts.map +1 -1
  33. package/dist/hitl/providers/tui.js +4 -0
  34. package/dist/hitl/providers/tui.js.map +1 -1
  35. package/dist/hitl/providers/types.d.ts +2 -0
  36. package/dist/hitl/providers/types.d.ts.map +1 -1
  37. package/dist/middleware/chain-builder.d.ts.map +1 -1
  38. package/dist/middleware/chain-builder.js +3 -1
  39. package/dist/middleware/chain-builder.js.map +1 -1
  40. package/dist/middleware/core/execute.d.ts.map +1 -1
  41. package/dist/middleware/core/execute.js +9 -3
  42. package/dist/middleware/core/execute.js.map +1 -1
  43. package/dist/middleware/core/hitl-gate.d.ts.map +1 -1
  44. package/dist/middleware/core/hitl-gate.js +16 -3
  45. package/dist/middleware/core/hitl-gate.js.map +1 -1
  46. package/dist/middleware/core/sandbox.d.ts +3 -0
  47. package/dist/middleware/core/sandbox.d.ts.map +1 -0
  48. package/dist/middleware/core/sandbox.js +15 -0
  49. package/dist/middleware/core/sandbox.js.map +1 -0
  50. package/dist/pool/http-client.d.ts.map +1 -1
  51. package/dist/pool/http-client.js +3 -5
  52. package/dist/pool/http-client.js.map +1 -1
  53. package/dist/registry/registry.d.ts +1 -1
  54. package/dist/registry/registry.d.ts.map +1 -1
  55. package/dist/registry/registry.js +36 -18
  56. package/dist/registry/registry.js.map +1 -1
  57. package/dist/sandbox/index.d.ts +39 -0
  58. package/dist/sandbox/index.d.ts.map +1 -0
  59. package/dist/sandbox/index.js +147 -0
  60. package/dist/sandbox/index.js.map +1 -0
  61. package/dist/tools/exec.d.ts +2 -1
  62. package/dist/tools/exec.d.ts.map +1 -1
  63. package/dist/tools/exec.js +5 -2
  64. package/dist/tools/exec.js.map +1 -1
  65. package/dist/transport/http-server.d.ts +7 -0
  66. package/dist/transport/http-server.d.ts.map +1 -0
  67. package/dist/transport/http-server.js +93 -0
  68. package/dist/transport/http-server.js.map +1 -0
  69. package/dist/types.d.ts +1 -0
  70. package/dist/types.d.ts.map +1 -1
  71. package/examples/gateway.yaml +30 -0
  72. package/examples/sandbox-presets.yaml +142 -0
  73. package/package.json +7 -1
  74. package/schema.json +293 -3
@@ -0,0 +1,93 @@
1
+ import { randomUUID, timingSafeEqual } from 'crypto';
2
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
+ import { createAgentServer, connectAgentServer } from './agent-server.js';
4
+ import { childLogger } from '../util/logger.js';
5
+ const log = childLogger('http-server');
6
+ function constantTimeEqual(a, b) {
7
+ const bufA = Buffer.from(a);
8
+ const bufB = Buffer.from(b);
9
+ if (bufA.length !== bufB.length)
10
+ return false;
11
+ return timingSafeEqual(bufA, bufB);
12
+ }
13
+ // eslint-disable-next-line @typescript-eslint/require-await
14
+ export async function httpServerPlugin(app, opts) {
15
+ const { secret } = opts;
16
+ const sessions = new Map();
17
+ // Don't parse request bodies — handleRequest reads the raw stream.
18
+ app.removeAllContentTypeParsers();
19
+ app.addContentTypeParser('*', (_req, _payload, done) => {
20
+ done(null);
21
+ });
22
+ function checkAgentAuth(request, reply, deps) {
23
+ const token = deps.agentConfig.token;
24
+ if (token) {
25
+ const auth = request.headers.authorization ?? '';
26
+ if (!constantTimeEqual(auth, `Bearer ${token}`)) {
27
+ reply.status(401).send({ error: 'Unauthorized' });
28
+ return false;
29
+ }
30
+ return true;
31
+ }
32
+ if (secret) {
33
+ const auth = request.headers.authorization ?? '';
34
+ if (!constantTimeEqual(auth, `Bearer ${secret}`)) {
35
+ reply.status(401).send({ error: 'Unauthorized' });
36
+ return false;
37
+ }
38
+ }
39
+ return true;
40
+ }
41
+ async function handleMcpRequest(request, reply) {
42
+ const { profileId } = request.params;
43
+ const deps = opts.getDeps(profileId);
44
+ if (!deps) {
45
+ return reply.status(404).send({ error: `Unknown agent profile: ${profileId}` });
46
+ }
47
+ if (!checkAgentAuth(request, reply, deps))
48
+ return;
49
+ const sessionId = request.headers['mcp-session-id'];
50
+ let transport;
51
+ if (sessionId) {
52
+ const session = sessions.get(sessionId);
53
+ if (!session) {
54
+ return reply.status(404).send({ error: `Session not found: ${sessionId}` });
55
+ }
56
+ if (session.profileId !== profileId) {
57
+ return reply.status(403).send({ error: 'Session does not belong to this agent' });
58
+ }
59
+ transport = session.transport;
60
+ }
61
+ else {
62
+ // New session — create transport + MCP server before the initialize handshake.
63
+ const ac = new AbortController();
64
+ transport = new StreamableHTTPServerTransport({
65
+ sessionIdGenerator: () => randomUUID(),
66
+ onsessioninitialized: (id) => {
67
+ sessions.set(id, { transport, ac, profileId });
68
+ log.info({ profileId, sessionId: id }, 'HTTP session initialized');
69
+ },
70
+ onsessionclosed: (id) => {
71
+ sessions.delete(id);
72
+ ac.abort();
73
+ log.info({ profileId, sessionId: id }, 'HTTP session closed');
74
+ },
75
+ });
76
+ const server = createAgentServer({ ...deps, signal: ac.signal });
77
+ await connectAgentServer(server, transport);
78
+ transport.onclose = () => {
79
+ const id = transport.sessionId;
80
+ if (id)
81
+ sessions.delete(id);
82
+ ac.abort();
83
+ };
84
+ }
85
+ // Hand off raw Node.js req/res — Fastify must not touch the response after this.
86
+ reply.hijack();
87
+ await transport.handleRequest(request.raw, reply.raw);
88
+ }
89
+ app.post('/agents/:profileId/mcp', handleMcpRequest);
90
+ app.get('/agents/:profileId/mcp', handleMcpRequest);
91
+ app.delete('/agents/:profileId/mcp', handleMcpRequest);
92
+ }
93
+ //# sourceMappingURL=http-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../../src/transport/http-server.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ export interface ToolCall {
2
2
  tool: string;
3
3
  args: Record<string, unknown>;
4
4
  agentId: string;
5
+ meta?: Record<string, unknown>;
5
6
  }
6
7
  export interface ToolResult {
7
8
  success: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1D"}
@@ -31,6 +31,19 @@ providers:
31
31
  exec: builtin
32
32
  http: builtin
33
33
 
34
+ # Optional reusable sandbox presets for policy-wrapped tool variants.
35
+ # See examples/sandbox-presets.yaml for a focused end-to-end example.
36
+ # sandbox_presets:
37
+ # local_transform:
38
+ # filesystem:
39
+ # allow_read: ['.']
40
+ # allow_write: ['/tmp', '/private/tmp']
41
+ # deny_read: ['~/.ssh', '~/.aws', '.env']
42
+ # deny_write: ['.']
43
+ # network:
44
+ # allowed_domains: []
45
+ # denied_domains: []
46
+
34
47
  # Agents
35
48
  agents:
36
49
  # Helena: full-access developer agent with approval on destructive ops
@@ -61,6 +74,23 @@ agents:
61
74
  domain_allowlist:
62
75
  - 'api.github.com'
63
76
  - '*.sentry.io'
77
+ # sandbox:
78
+ # enabled: true
79
+ # presets: ['local_transform']
80
+ # tool_overrides:
81
+ # python/sandboxed:
82
+ # alias_of: 'exec/run'
83
+ # description: 'Run Python for local transforms only'
84
+ # python/full:
85
+ # alias_of: 'exec/run'
86
+ # description: 'Run Python with broader permissions after approval'
87
+ # sandbox:
88
+ # filesystem:
89
+ # allow_write: ['.', '/tmp', '/private/tmp']
90
+ # deny_write: []
91
+ # network:
92
+ # allowed_domains: ['pypi.org', '*.pythonhosted.org']
93
+ # denied_domains: []
64
94
 
65
95
  # Claude Code: read-only, no approval needed
66
96
  claude-code:
@@ -0,0 +1,142 @@
1
+ # Sandbox presets + tool variant example.
2
+ #
3
+ # Goal:
4
+ # - give agents a fast-path tool that is broadly allowed because it runs in a
5
+ # tight sandbox
6
+ # - keep a second full-power variant that still requires approval
7
+ #
8
+ # Run: npx tsx src/index.ts --agent claude-code --config examples/sandbox-presets.yaml
9
+
10
+ providers:
11
+ exec: builtin
12
+
13
+ # Reusable sandbox building blocks.
14
+ # These can be referenced by agents and by individual tool variants.
15
+ sandbox_presets:
16
+ local_transform:
17
+ filesystem:
18
+ # Let the agent read the repo, but only write to temp space.
19
+ allow_read:
20
+ - '.'
21
+ allow_write:
22
+ - '/tmp'
23
+ - '/private/tmp'
24
+ # Additive deny rules protect common secret locations.
25
+ deny_read:
26
+ - '~/.ssh'
27
+ - '~/.aws'
28
+ - '~/.config/gcloud'
29
+ - '.env'
30
+ # Prevent writes back into the repo by default.
31
+ deny_write:
32
+ - '.'
33
+ network:
34
+ # Empty allowlist means no outbound network.
35
+ allowed_domains: []
36
+ denied_domains: []
37
+
38
+ github_only:
39
+ network:
40
+ allowed_domains:
41
+ - 'github.com'
42
+ - '*.github.com'
43
+ - 'api.github.com'
44
+ denied_domains: []
45
+
46
+ agents:
47
+ claude-code:
48
+ allow:
49
+ - 'python/sandboxed'
50
+ - 'node/sandboxed'
51
+ ask:
52
+ - 'python/full'
53
+ - 'python/github'
54
+ - 'node/full'
55
+ deny:
56
+ - 'exec/run'
57
+
58
+ # Agent-level sandbox defaults apply to any tool that resolves through the
59
+ # sandbox middleware, then tool-specific presets / overrides refine it.
60
+ sandbox:
61
+ enabled: true
62
+ presets:
63
+ - local_transform
64
+
65
+ tool_overrides:
66
+ # Safe fast path: same underlying capability, but strongly sandboxed.
67
+ python/sandboxed:
68
+ alias_of: 'exec/run'
69
+ description: 'Run Python for local JSON/text transformations only'
70
+
71
+ # Full-power variant: same base tool, but leave it approval-gated.
72
+ python/full:
73
+ alias_of: 'exec/run'
74
+ description: 'Run Python with normal permissions after approval'
75
+ sandbox:
76
+ filesystem:
77
+ # Override allow_write so approved runs can modify the repo.
78
+ allow_write:
79
+ - '.'
80
+ - '/tmp'
81
+ - '/private/tmp'
82
+ deny_write: []
83
+ network:
84
+ # Example broad approved networking.
85
+ allowed_domains:
86
+ - 'pypi.org'
87
+ - '*.pythonhosted.org'
88
+ denied_domains: []
89
+
90
+ # Middle ground: GitHub-only network for scripts that need API access.
91
+ python/github:
92
+ alias_of: 'exec/run'
93
+ description: 'Run Python with GitHub-only network access after approval'
94
+ sandbox_presets:
95
+ - github_only
96
+
97
+ node/sandboxed:
98
+ alias_of: 'exec/run'
99
+ description: 'Run Node.js for local transformations only'
100
+
101
+ node/full:
102
+ alias_of: 'exec/run'
103
+ description: 'Run Node.js with broader permissions after approval'
104
+ sandbox:
105
+ filesystem:
106
+ allow_write:
107
+ - '.'
108
+ - '/tmp'
109
+ - '/private/tmp'
110
+ deny_write: []
111
+ network:
112
+ allowed_domains:
113
+ - 'registry.npmjs.org'
114
+ - '*.npmjs.org'
115
+ denied_domains: []
116
+
117
+ exec:
118
+ # Example shell policy for the underlying exec provider.
119
+ # The tool permission still controls whether the tool can be called at all;
120
+ # these patterns constrain the command strings passed into exec/run.
121
+ allow:
122
+ - 'python3 -c *'
123
+ - 'python -c *'
124
+ - 'node -e *'
125
+ ask:
126
+ - 'python3 *'
127
+ - 'python *'
128
+ - 'node *'
129
+ deny:
130
+ - 'sudo *'
131
+ - 'rm -rf *'
132
+
133
+ approvals:
134
+ provider:
135
+ type: stdio
136
+ timeout_ms: 300000
137
+ batch_window_ms: 5000
138
+
139
+ audit:
140
+ db_path: ':memory:'
141
+ retention_days: 1
142
+ redact_fields: []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "airlock-bot",
3
- "version": "0.2.19",
3
+ "version": "0.2.21",
4
4
  "description": "Permissions-aware MCP gateway with human-in-the-loop approval for AI agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,6 +40,10 @@
40
40
  "build": "tsc",
41
41
  "dev": "tsx src/index.ts",
42
42
  "configure-agent": "tsx scripts/configure-agent.ts",
43
+ "docs:dev": "vitepress dev docs",
44
+ "docs:llms": "tsx scripts/generate-llms.ts",
45
+ "docs:build": "npm run docs:llms && vitepress build docs",
46
+ "docs:preview": "vitepress preview docs",
43
47
  "test": "vitest",
44
48
  "typecheck": "tsc --noEmit",
45
49
  "lint": "eslint src",
@@ -50,6 +54,7 @@
50
54
  "prepublishOnly": "npm run schema && npm run build"
51
55
  },
52
56
  "dependencies": {
57
+ "@anthropic-ai/sandbox-runtime": "^0.0.42",
53
58
  "@apidevtools/swagger-parser": "^12.1.0",
54
59
  "@modelcontextprotocol/sdk": "^1.27.1",
55
60
  "ai": "^6.0.116",
@@ -77,6 +82,7 @@
77
82
  "tsx": "^4.7.0",
78
83
  "typescript": "^5.4.0",
79
84
  "typescript-eslint": "^8.57.0",
85
+ "vitepress": "^1.6.4",
80
86
  "vitest": "^3.0.0",
81
87
  "zod-to-json-schema": "^3.25.1"
82
88
  }
package/schema.json CHANGED
@@ -132,6 +132,72 @@
132
132
  },
133
133
  "default": {}
134
134
  },
135
+ "sandbox_presets": {
136
+ "type": "object",
137
+ "additionalProperties": {
138
+ "type": "object",
139
+ "properties": {
140
+ "filesystem": {
141
+ "type": "object",
142
+ "properties": {
143
+ "allow_write": {
144
+ "type": "array",
145
+ "items": {
146
+ "type": "string"
147
+ },
148
+ "default": [
149
+ ".",
150
+ "/tmp"
151
+ ]
152
+ },
153
+ "deny_read": {
154
+ "type": "array",
155
+ "items": {
156
+ "type": "string"
157
+ },
158
+ "default": []
159
+ },
160
+ "deny_write": {
161
+ "type": "array",
162
+ "items": {
163
+ "type": "string"
164
+ },
165
+ "default": []
166
+ },
167
+ "allow_read": {
168
+ "type": "array",
169
+ "items": {
170
+ "type": "string"
171
+ }
172
+ }
173
+ },
174
+ "additionalProperties": false
175
+ },
176
+ "network": {
177
+ "type": "object",
178
+ "properties": {
179
+ "allowed_domains": {
180
+ "type": "array",
181
+ "items": {
182
+ "type": "string"
183
+ },
184
+ "default": []
185
+ },
186
+ "denied_domains": {
187
+ "type": "array",
188
+ "items": {
189
+ "type": "string"
190
+ },
191
+ "default": []
192
+ }
193
+ },
194
+ "additionalProperties": false
195
+ }
196
+ },
197
+ "additionalProperties": false
198
+ },
199
+ "default": {}
200
+ },
135
201
  "clis": {
136
202
  "type": "object",
137
203
  "additionalProperties": {
@@ -349,9 +415,84 @@
349
415
  "description": {
350
416
  "type": "string"
351
417
  },
352
- "trusted": {
353
- "type": "boolean",
354
- "default": false
418
+ "alias_of": {
419
+ "type": "string"
420
+ },
421
+ "sandbox_presets": {
422
+ "anyOf": [
423
+ {
424
+ "type": "string"
425
+ },
426
+ {
427
+ "type": "array",
428
+ "items": {
429
+ "type": "string"
430
+ }
431
+ }
432
+ ],
433
+ "default": []
434
+ },
435
+ "sandbox": {
436
+ "type": "object",
437
+ "properties": {
438
+ "filesystem": {
439
+ "type": "object",
440
+ "properties": {
441
+ "allow_write": {
442
+ "type": "array",
443
+ "items": {
444
+ "type": "string"
445
+ },
446
+ "default": [
447
+ ".",
448
+ "/tmp"
449
+ ]
450
+ },
451
+ "deny_read": {
452
+ "type": "array",
453
+ "items": {
454
+ "type": "string"
455
+ },
456
+ "default": []
457
+ },
458
+ "deny_write": {
459
+ "type": "array",
460
+ "items": {
461
+ "type": "string"
462
+ },
463
+ "default": []
464
+ },
465
+ "allow_read": {
466
+ "type": "array",
467
+ "items": {
468
+ "type": "string"
469
+ }
470
+ }
471
+ },
472
+ "additionalProperties": false
473
+ },
474
+ "network": {
475
+ "type": "object",
476
+ "properties": {
477
+ "allowed_domains": {
478
+ "type": "array",
479
+ "items": {
480
+ "type": "string"
481
+ },
482
+ "default": []
483
+ },
484
+ "denied_domains": {
485
+ "type": "array",
486
+ "items": {
487
+ "type": "string"
488
+ },
489
+ "default": []
490
+ }
491
+ },
492
+ "additionalProperties": false
493
+ }
494
+ },
495
+ "additionalProperties": false
355
496
  }
356
497
  },
357
498
  "additionalProperties": false
@@ -419,6 +560,155 @@
419
560
  "additionalProperties": false,
420
561
  "default": {}
421
562
  },
563
+ "sandbox": {
564
+ "type": "object",
565
+ "properties": {
566
+ "enabled": {
567
+ "type": "boolean",
568
+ "default": false
569
+ },
570
+ "presets": {
571
+ "anyOf": [
572
+ {
573
+ "type": "string"
574
+ },
575
+ {
576
+ "type": "array",
577
+ "items": {
578
+ "type": "string"
579
+ }
580
+ }
581
+ ],
582
+ "default": []
583
+ },
584
+ "filesystem": {
585
+ "type": "object",
586
+ "properties": {
587
+ "allow_write": {
588
+ "type": "array",
589
+ "items": {
590
+ "type": "string"
591
+ },
592
+ "default": [
593
+ ".",
594
+ "/tmp"
595
+ ]
596
+ },
597
+ "deny_read": {
598
+ "type": "array",
599
+ "items": {
600
+ "type": "string"
601
+ },
602
+ "default": []
603
+ },
604
+ "deny_write": {
605
+ "type": "array",
606
+ "items": {
607
+ "type": "string"
608
+ },
609
+ "default": []
610
+ },
611
+ "allow_read": {
612
+ "type": "array",
613
+ "items": {
614
+ "type": "string"
615
+ }
616
+ }
617
+ },
618
+ "additionalProperties": false,
619
+ "default": {}
620
+ },
621
+ "network": {
622
+ "type": "object",
623
+ "properties": {
624
+ "allowed_domains": {
625
+ "type": "array",
626
+ "items": {
627
+ "type": "string"
628
+ },
629
+ "default": []
630
+ },
631
+ "denied_domains": {
632
+ "type": "array",
633
+ "items": {
634
+ "type": "string"
635
+ },
636
+ "default": []
637
+ }
638
+ },
639
+ "additionalProperties": false,
640
+ "default": {}
641
+ },
642
+ "overrides": {
643
+ "type": "object",
644
+ "additionalProperties": {
645
+ "type": "object",
646
+ "properties": {
647
+ "filesystem": {
648
+ "type": "object",
649
+ "properties": {
650
+ "allow_write": {
651
+ "type": "array",
652
+ "items": {
653
+ "type": "string"
654
+ },
655
+ "default": [
656
+ ".",
657
+ "/tmp"
658
+ ]
659
+ },
660
+ "deny_read": {
661
+ "type": "array",
662
+ "items": {
663
+ "type": "string"
664
+ },
665
+ "default": []
666
+ },
667
+ "deny_write": {
668
+ "type": "array",
669
+ "items": {
670
+ "type": "string"
671
+ },
672
+ "default": []
673
+ },
674
+ "allow_read": {
675
+ "type": "array",
676
+ "items": {
677
+ "type": "string"
678
+ }
679
+ }
680
+ },
681
+ "additionalProperties": false
682
+ },
683
+ "network": {
684
+ "type": "object",
685
+ "properties": {
686
+ "allowed_domains": {
687
+ "type": "array",
688
+ "items": {
689
+ "type": "string"
690
+ },
691
+ "default": []
692
+ },
693
+ "denied_domains": {
694
+ "type": "array",
695
+ "items": {
696
+ "type": "string"
697
+ },
698
+ "default": []
699
+ }
700
+ },
701
+ "additionalProperties": false
702
+ }
703
+ },
704
+ "additionalProperties": false
705
+ },
706
+ "default": {}
707
+ }
708
+ },
709
+ "additionalProperties": false,
710
+ "default": {}
711
+ },
422
712
  "middleware": {
423
713
  "type": "array",
424
714
  "items": {