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.
- package/README.md +162 -24
- package/dist/backend/cli/adapter.d.ts.map +1 -1
- package/dist/backend/cli/adapter.js +7 -1
- package/dist/backend/cli/adapter.js.map +1 -1
- package/dist/backend/exec-adapter.d.ts.map +1 -1
- package/dist/backend/exec-adapter.js +2 -1
- package/dist/backend/exec-adapter.js.map +1 -1
- package/dist/backend/factory.d.ts.map +1 -1
- package/dist/backend/factory.js +3 -2
- package/dist/backend/factory.js.map +1 -1
- package/dist/backend/mcp-adapter.d.ts +7 -1
- package/dist/backend/mcp-adapter.d.ts.map +1 -1
- package/dist/backend/mcp-adapter.js +49 -1
- package/dist/backend/mcp-adapter.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +23 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +1518 -16
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +151 -3
- package/dist/config/schema.js.map +1 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +5 -0
- package/dist/gateway.js.map +1 -1
- package/dist/hitl/engine.d.ts +2 -0
- package/dist/hitl/engine.d.ts.map +1 -1
- package/dist/hitl/engine.js +2 -0
- package/dist/hitl/engine.js.map +1 -1
- package/dist/hitl/formatter.d.ts.map +1 -1
- package/dist/hitl/formatter.js +17 -1
- package/dist/hitl/formatter.js.map +1 -1
- package/dist/hitl/providers/tui.d.ts.map +1 -1
- package/dist/hitl/providers/tui.js +4 -0
- package/dist/hitl/providers/tui.js.map +1 -1
- package/dist/hitl/providers/types.d.ts +2 -0
- package/dist/hitl/providers/types.d.ts.map +1 -1
- package/dist/middleware/chain-builder.d.ts.map +1 -1
- package/dist/middleware/chain-builder.js +3 -1
- package/dist/middleware/chain-builder.js.map +1 -1
- package/dist/middleware/core/execute.d.ts.map +1 -1
- package/dist/middleware/core/execute.js +9 -3
- package/dist/middleware/core/execute.js.map +1 -1
- package/dist/middleware/core/hitl-gate.d.ts.map +1 -1
- package/dist/middleware/core/hitl-gate.js +16 -3
- package/dist/middleware/core/hitl-gate.js.map +1 -1
- package/dist/middleware/core/sandbox.d.ts +3 -0
- package/dist/middleware/core/sandbox.d.ts.map +1 -0
- package/dist/middleware/core/sandbox.js +15 -0
- package/dist/middleware/core/sandbox.js.map +1 -0
- package/dist/pool/http-client.d.ts.map +1 -1
- package/dist/pool/http-client.js +3 -5
- package/dist/pool/http-client.js.map +1 -1
- package/dist/registry/registry.d.ts +1 -1
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +36 -18
- package/dist/registry/registry.js.map +1 -1
- package/dist/sandbox/index.d.ts +39 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +147 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/tools/exec.d.ts +2 -1
- package/dist/tools/exec.d.ts.map +1 -1
- package/dist/tools/exec.js +5 -2
- package/dist/tools/exec.js.map +1 -1
- package/dist/transport/http-server.d.ts +7 -0
- package/dist/transport/http-server.d.ts.map +1 -0
- package/dist/transport/http-server.js +93 -0
- package/dist/transport/http-server.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/examples/gateway.yaml +30 -0
- package/examples/sandbox-presets.yaml +142 -0
- package/package.json +7 -1
- 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
package/dist/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/examples/gateway.yaml
CHANGED
|
@@ -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.
|
|
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
|
-
"
|
|
353
|
-
"type": "
|
|
354
|
-
|
|
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": {
|