airlock-bot 0.2.35 → 0.2.37

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 +31 -1
  2. package/dist/audit/api.d.ts +2 -0
  3. package/dist/audit/api.d.ts.map +1 -1
  4. package/dist/audit/api.js +3 -13
  5. package/dist/audit/api.js.map +1 -1
  6. package/dist/config/loader.d.ts.map +1 -1
  7. package/dist/config/loader.js +41 -1
  8. package/dist/config/loader.js.map +1 -1
  9. package/dist/config/profiles.d.ts +3 -6
  10. package/dist/config/profiles.d.ts.map +1 -1
  11. package/dist/config/profiles.js +52 -19
  12. package/dist/config/profiles.js.map +1 -1
  13. package/dist/config/schema.d.ts +368 -8
  14. package/dist/config/schema.d.ts.map +1 -1
  15. package/dist/config/schema.js +35 -0
  16. package/dist/config/schema.js.map +1 -1
  17. package/dist/configure-web/cli.d.ts +41 -2
  18. package/dist/configure-web/cli.d.ts.map +1 -1
  19. package/dist/configure-web/cli.js +1283 -55
  20. package/dist/configure-web/cli.js.map +1 -1
  21. package/dist/gateway.d.ts +7 -1
  22. package/dist/gateway.d.ts.map +1 -1
  23. package/dist/gateway.js +81 -26
  24. package/dist/gateway.js.map +1 -1
  25. package/dist/hitl/api.d.ts +2 -0
  26. package/dist/hitl/api.d.ts.map +1 -1
  27. package/dist/hitl/api.js +3 -13
  28. package/dist/hitl/api.js.map +1 -1
  29. package/dist/hitl/approval-dashboard.d.ts +19 -0
  30. package/dist/hitl/approval-dashboard.d.ts.map +1 -0
  31. package/dist/hitl/approval-dashboard.js +148 -0
  32. package/dist/hitl/approval-dashboard.js.map +1 -0
  33. package/dist/hitl/provider-factory.js +1 -1
  34. package/dist/hitl/provider-factory.js.map +1 -1
  35. package/dist/hitl/providers/dashboard.d.ts +4 -5
  36. package/dist/hitl/providers/dashboard.d.ts.map +1 -1
  37. package/dist/hitl/providers/dashboard.js +29 -469
  38. package/dist/hitl/providers/dashboard.js.map +1 -1
  39. package/dist/hook/api.d.ts +2 -0
  40. package/dist/hook/api.d.ts.map +1 -1
  41. package/dist/hook/api.js +3 -13
  42. package/dist/hook/api.js.map +1 -1
  43. package/dist/index.js +29 -4
  44. package/dist/index.js.map +1 -1
  45. package/dist/middleware/chain-builder.d.ts +1 -1
  46. package/dist/middleware/chain-builder.d.ts.map +1 -1
  47. package/dist/middleware/chain-builder.js +4 -2
  48. package/dist/middleware/chain-builder.js.map +1 -1
  49. package/dist/middleware/core/arg-policy.d.ts +12 -0
  50. package/dist/middleware/core/arg-policy.d.ts.map +1 -0
  51. package/dist/middleware/core/arg-policy.js +91 -0
  52. package/dist/middleware/core/arg-policy.js.map +1 -0
  53. package/dist/security/request.d.ts +14 -0
  54. package/dist/security/request.d.ts.map +1 -0
  55. package/dist/security/request.js +47 -0
  56. package/dist/security/request.js.map +1 -0
  57. package/dist/tools/api.d.ts +2 -0
  58. package/dist/tools/api.d.ts.map +1 -1
  59. package/dist/tools/api.js +3 -13
  60. package/dist/tools/api.js.map +1 -1
  61. package/dist/transport/http-server.d.ts +2 -0
  62. package/dist/transport/http-server.d.ts.map +1 -1
  63. package/dist/transport/http-server.js +9 -22
  64. package/dist/transport/http-server.js.map +1 -1
  65. package/dist/transport/sse-server.d.ts +2 -0
  66. package/dist/transport/sse-server.d.ts.map +1 -1
  67. package/dist/transport/sse-server.js +9 -26
  68. package/dist/transport/sse-server.js.map +1 -1
  69. package/examples/docker-compose.yaml +63 -0
  70. package/examples/docker-gateway.yaml +61 -0
  71. package/examples/gateway.yaml +7 -0
  72. package/examples/profiles.yaml +4 -2
  73. package/package.json +1 -1
  74. package/schema.json +79 -0
@@ -1,17 +1,10 @@
1
- import { timingSafeEqual } from 'crypto';
2
1
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
3
2
  import { createAgentServer, connectAgentServer } from './agent-server.js';
4
3
  import { childLogger } from '../util/logger.js';
4
+ import { checkBearerAuth, checkOrigin, checkRequestSecurity } from '../security/request.js';
5
5
  const log = childLogger('sse-server');
6
6
  /** Interval between SSE keep-alive pings (ms). Keeps connections alive through NAT/firewalls. */
7
7
  const PING_INTERVAL_MS = 30_000;
8
- function constantTimeEqual(a, b) {
9
- const bufA = Buffer.from(a);
10
- const bufB = Buffer.from(b);
11
- if (bufA.length !== bufB.length)
12
- return false;
13
- return timingSafeEqual(bufA, bufB);
14
- }
15
8
  // eslint-disable-next-line @typescript-eslint/require-await
16
9
  export async function sseServerPlugin(app, opts) {
17
10
  const { secret } = opts;
@@ -23,24 +16,17 @@ export async function sseServerPlugin(app, opts) {
23
16
  done(null);
24
17
  });
25
18
  function checkAgentAuth(request, reply, deps) {
19
+ if (!checkOrigin(request, reply, opts.allowedOrigins))
20
+ return false;
26
21
  const token = deps.agentConfig.token;
27
22
  if (token) {
28
- const auth = request.headers.authorization ?? '';
29
- if (!constantTimeEqual(auth, `Bearer ${token}`)) {
30
- reply.status(401).send({ error: 'Unauthorized' });
31
- return false;
32
- }
33
- return true;
23
+ return checkBearerAuth(request, reply, { secret: token, authRequired: true });
34
24
  }
35
25
  // No per-agent token — fall back to global api_secret
36
- if (secret) {
37
- const auth = request.headers.authorization ?? '';
38
- if (!constantTimeEqual(auth, `Bearer ${secret}`)) {
39
- reply.status(401).send({ error: 'Unauthorized' });
40
- return false;
41
- }
42
- }
43
- return true;
26
+ return checkBearerAuth(request, reply, {
27
+ secret,
28
+ authRequired: opts.authRequired,
29
+ });
44
30
  }
45
31
  // Auth for non-agent endpoints (management API)
46
32
  app.addHook('preHandler', async (request, reply) => {
@@ -48,11 +34,8 @@ export async function sseServerPlugin(app, opts) {
48
34
  // Agent endpoints handle their own auth
49
35
  if (url.startsWith('/agents/'))
50
36
  return;
51
- if (!secret)
37
+ if (!checkRequestSecurity(request, reply, opts)) {
52
38
  return;
53
- const auth = request.headers.authorization ?? '';
54
- if (!constantTimeEqual(auth, `Bearer ${secret}`)) {
55
- return reply.status(401).send({ error: 'Unauthorized' });
56
39
  }
57
40
  });
58
41
  app.get('/agents/:profileId/sse', async (request, reply) => {
@@ -1 +1 @@
1
- {"version":3,"file":"sse-server.js","sourceRoot":"","sources":["../../src/transport/sse-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sse-server.js","sourceRoot":"","sources":["../../src/transport/sse-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ services:
2
+ airlock-gateway:
3
+ build:
4
+ context: ..
5
+ dockerfile: Dockerfile
6
+ image: airlock-bot:local
7
+ command: gateway --config /config/airlock.yaml
8
+ restart: unless-stopped
9
+ env_file:
10
+ - .env
11
+ environment:
12
+ AIRLOCK_CONFIG: /config/airlock.yaml
13
+ AIRLOCK_HEALTH_PORT: '4111'
14
+ volumes:
15
+ # Runtime gateway can hot-reload this file but cannot modify policy.
16
+ - ./airlock-config:/config:ro
17
+ - airlock-data:/data
18
+ # Keep npx-installed MCP servers cached across restarts.
19
+ - airlock-npm-cache:/home/airlock/.npm
20
+ ports:
21
+ # Bind to loopback by default. Put your TLS/auth proxy on the same host,
22
+ # or change these bindings only for a trusted private network.
23
+ - 127.0.0.1:4111:4111
24
+ read_only: true
25
+ tmpfs:
26
+ - /tmp:rw,nosuid,nodev,size=256m
27
+ cap_drop:
28
+ - ALL
29
+ security_opt:
30
+ - no-new-privileges:true
31
+ # Add reverse-proxy labels or service discovery metadata here if your
32
+ # platform uses container labels.
33
+
34
+ airlock-dashboard:
35
+ image: airlock-bot:local
36
+ command: dashboard --config /config/airlock.yaml --host 0.0.0.0 --port 4112 --gateway-url http://airlock-gateway:4111
37
+ restart: unless-stopped
38
+ env_file:
39
+ - .env
40
+ environment:
41
+ AIRLOCK_CONFIG: /config/airlock.yaml
42
+ AIRLOCK_GATEWAY_SECRET: ${AIRLOCK_API_SECRET}
43
+ AIRLOCK_HEALTH_PORT: '4112'
44
+ volumes:
45
+ # Dashboard owns config mutation and writes /config/airlock.bak.
46
+ - ./airlock-config:/config
47
+ ports:
48
+ - 127.0.0.1:4112:4112
49
+ read_only: true
50
+ tmpfs:
51
+ - /tmp:rw,nosuid,nodev,size=128m
52
+ cap_drop:
53
+ - ALL
54
+ security_opt:
55
+ - no-new-privileges:true
56
+ depends_on:
57
+ - airlock-gateway
58
+ # Add dashboard-specific reverse-proxy labels here. Protect this route with
59
+ # human authentication.
60
+
61
+ volumes:
62
+ airlock-data:
63
+ airlock-npm-cache:
@@ -0,0 +1,61 @@
1
+ # yaml-language-server: $schema=../schema.json
2
+ # Minimal Docker/VPS-oriented config. Copy this file next to
3
+ # examples/docker-compose.yaml, create an .env file with the referenced secrets,
4
+ # and edit providers/agents for your deployment.
5
+
6
+ server:
7
+ port: 4111
8
+ host: 0.0.0.0
9
+ api_secret: ${AIRLOCK_API_SECRET}
10
+ auth_required: true
11
+ require_agent_tokens: true
12
+ allowed_origins:
13
+ - https://airlock.example.com
14
+ expose_management_api: true
15
+ expose_tools_api: false
16
+ expose_hook_api: false
17
+
18
+ providers:
19
+ http: builtin
20
+ # Add stdio/SSE/HTTP MCP providers here. If a provider uses npx, the compose
21
+ # example persists /home/airlock/.npm so packages are cached across restarts.
22
+
23
+ agents:
24
+ example-agent:
25
+ token: ${EXAMPLE_AGENT_AIRLOCK_TOKEN}
26
+ allow:
27
+ - http/get
28
+ ask:
29
+ - http/post
30
+ http:
31
+ domain_allowlist:
32
+ - api.github.com
33
+
34
+ approvals:
35
+ provider:
36
+ type: dashboard
37
+ host: 0.0.0.0
38
+ port: 4112
39
+ timeout_ms: 300000
40
+
41
+ security:
42
+ blocked_hosts:
43
+ - localhost
44
+ - 127.0.0.1
45
+ - '::1'
46
+ - '*.local'
47
+ - '10.*'
48
+ - '172.16.*'
49
+ - '192.168.*'
50
+ - '169.254.*'
51
+ allowed_local: []
52
+
53
+ audit:
54
+ db_path: /data/airlock-audit.db
55
+ retention_days: 90
56
+ redact_fields:
57
+ - password
58
+ - token
59
+ - secret
60
+ - key
61
+ - authorization
@@ -6,6 +6,13 @@ server:
6
6
  port: 4111
7
7
  host: 127.0.0.1
8
8
  # api_secret: ${AIRLOCK_API_SECRET}
9
+ # auth_required: true
10
+ # require_agent_tokens: true
11
+ # allowed_origins:
12
+ # - https://airlock.example.com
13
+ # expose_management_api: false
14
+ # expose_tools_api: false
15
+ # expose_hook_api: false
9
16
 
10
17
  # Tool providers — MCP servers and builtins
11
18
  providers:
@@ -1,8 +1,9 @@
1
1
  # yaml-language-server: $schema=../schema.json
2
2
  # Composable profiles — define reusable permission sets, then mix them into agents.
3
3
  #
4
- # Profiles are union-merged: an agent that extends [readonly, github-write]
5
- # gets all allow/ask patterns from both profiles, plus its own.
4
+ # Profiles are union-merged recursively: a profile or agent that extends
5
+ # [readonly, github-write] gets all allow/ask/deny patterns from both profiles,
6
+ # plus its own.
6
7
  # Precedence still applies: deny > ask > allow > default-deny.
7
8
  #
8
9
  # Run: npx tsx src/index.ts --agent helena --config examples/profiles.yaml
@@ -35,6 +36,7 @@ profiles:
35
36
  ask: []
36
37
 
37
38
  github-write:
39
+ extends: [readonly]
38
40
  allow:
39
41
  - 'github/create_issue'
40
42
  - 'github/create_pr'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "airlock-bot",
3
- "version": "0.2.35",
3
+ "version": "0.2.37",
4
4
  "description": "Permissions-aware MCP gateway with human-in-the-loop approval for AI agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/schema.json CHANGED
@@ -152,6 +152,13 @@
152
152
  "additionalProperties": {
153
153
  "type": "object",
154
154
  "properties": {
155
+ "extends": {
156
+ "type": "array",
157
+ "items": {
158
+ "type": "string"
159
+ },
160
+ "default": []
161
+ },
155
162
  "allow": {
156
163
  "type": "array",
157
164
  "items": {
@@ -558,12 +565,49 @@
558
565
  }
559
566
  },
560
567
  "additionalProperties": false
568
+ },
569
+ "args": {
570
+ "type": "object",
571
+ "additionalProperties": {
572
+ "type": "object",
573
+ "properties": {
574
+ "allow": {
575
+ "type": "array",
576
+ "items": {}
577
+ },
578
+ "equals": {},
579
+ "label": {
580
+ "type": "string"
581
+ }
582
+ },
583
+ "additionalProperties": false
584
+ }
561
585
  }
562
586
  },
563
587
  "additionalProperties": false
564
588
  },
565
589
  "default": {}
566
590
  },
591
+ "arg_policy": {
592
+ "type": "object",
593
+ "additionalProperties": {
594
+ "type": "object",
595
+ "additionalProperties": {
596
+ "type": "object",
597
+ "properties": {
598
+ "allow": {
599
+ "type": "array",
600
+ "items": {}
601
+ },
602
+ "equals": {},
603
+ "label": {
604
+ "type": "string"
605
+ }
606
+ },
607
+ "additionalProperties": false
608
+ }
609
+ }
610
+ },
567
611
  "exec": {
568
612
  "type": "object",
569
613
  "properties": {
@@ -1000,6 +1044,10 @@
1000
1044
  "type": "string",
1001
1045
  "const": "dashboard"
1002
1046
  },
1047
+ "host": {
1048
+ "type": "string",
1049
+ "default": "127.0.0.1"
1050
+ },
1003
1051
  "port": {
1004
1052
  "type": "integer",
1005
1053
  "minimum": 1,
@@ -1154,6 +1202,10 @@
1154
1202
  "type": "string",
1155
1203
  "const": "dashboard"
1156
1204
  },
1205
+ "host": {
1206
+ "type": "string",
1207
+ "default": "127.0.0.1"
1208
+ },
1157
1209
  "port": {
1158
1210
  "type": "integer",
1159
1211
  "minimum": 1,
@@ -1295,6 +1347,33 @@
1295
1347
  },
1296
1348
  "api_secret": {
1297
1349
  "type": "string"
1350
+ },
1351
+ "auth_required": {
1352
+ "type": "boolean",
1353
+ "default": false
1354
+ },
1355
+ "require_agent_tokens": {
1356
+ "type": "boolean",
1357
+ "default": false
1358
+ },
1359
+ "allowed_origins": {
1360
+ "type": "array",
1361
+ "items": {
1362
+ "type": "string"
1363
+ },
1364
+ "default": []
1365
+ },
1366
+ "expose_management_api": {
1367
+ "type": "boolean",
1368
+ "default": true
1369
+ },
1370
+ "expose_tools_api": {
1371
+ "type": "boolean",
1372
+ "default": true
1373
+ },
1374
+ "expose_hook_api": {
1375
+ "type": "boolean",
1376
+ "default": true
1298
1377
  }
1299
1378
  },
1300
1379
  "additionalProperties": false,