airlock-bot 0.0.1 → 0.2.2
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/LICENSE +21 -0
- package/README.md +337 -0
- package/airlock.service +27 -0
- package/dist/allowlist/engine.d.ts +9 -0
- package/dist/allowlist/engine.d.ts.map +1 -0
- package/dist/allowlist/engine.js +24 -0
- package/dist/allowlist/engine.js.map +1 -0
- package/dist/allowlist/pattern.d.ts +13 -0
- package/dist/allowlist/pattern.d.ts.map +1 -0
- package/dist/allowlist/pattern.js +33 -0
- package/dist/allowlist/pattern.js.map +1 -0
- package/dist/audit/api.d.ts +7 -0
- package/dist/audit/api.d.ts.map +1 -0
- package/dist/audit/api.js +31 -0
- package/dist/audit/api.js.map +1 -0
- package/dist/audit/db.d.ts +44 -0
- package/dist/audit/db.d.ts.map +1 -0
- package/dist/audit/db.js +121 -0
- package/dist/audit/db.js.map +1 -0
- package/dist/audit/logger.d.ts +25 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/logger.js +58 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/audit/redactor.d.ts +5 -0
- package/dist/audit/redactor.d.ts.map +1 -0
- package/dist/audit/redactor.js +27 -0
- package/dist/audit/redactor.js.map +1 -0
- package/dist/backend/cli/adapter.d.ts +23 -0
- package/dist/backend/cli/adapter.d.ts.map +1 -0
- package/dist/backend/cli/adapter.js +176 -0
- package/dist/backend/cli/adapter.js.map +1 -0
- package/dist/backend/cli/builder.d.ts +3 -0
- package/dist/backend/cli/builder.d.ts.map +1 -0
- package/dist/backend/cli/builder.js +52 -0
- package/dist/backend/cli/builder.js.map +1 -0
- package/dist/backend/cli/escaper.d.ts +2 -0
- package/dist/backend/cli/escaper.d.ts.map +1 -0
- package/dist/backend/cli/escaper.js +8 -0
- package/dist/backend/cli/escaper.js.map +1 -0
- package/dist/backend/exec-adapter.d.ts +13 -0
- package/dist/backend/exec-adapter.d.ts.map +1 -0
- package/dist/backend/exec-adapter.js +39 -0
- package/dist/backend/exec-adapter.js.map +1 -0
- package/dist/backend/factory.d.ts +9 -0
- package/dist/backend/factory.d.ts.map +1 -0
- package/dist/backend/factory.js +35 -0
- package/dist/backend/factory.js.map +1 -0
- package/dist/backend/http-adapter.d.ts +15 -0
- package/dist/backend/http-adapter.d.ts.map +1 -0
- package/dist/backend/http-adapter.js +39 -0
- package/dist/backend/http-adapter.js.map +1 -0
- package/dist/backend/mcp-adapter.d.ts +14 -0
- package/dist/backend/mcp-adapter.d.ts.map +1 -0
- package/dist/backend/mcp-adapter.js +38 -0
- package/dist/backend/mcp-adapter.js.map +1 -0
- package/dist/backend/openapi/adapter.d.ts +17 -0
- package/dist/backend/openapi/adapter.d.ts.map +1 -0
- package/dist/backend/openapi/adapter.js +144 -0
- package/dist/backend/openapi/adapter.js.map +1 -0
- package/dist/backend/openapi/parser.d.ts +21 -0
- package/dist/backend/openapi/parser.d.ts.map +1 -0
- package/dist/backend/openapi/parser.js +145 -0
- package/dist/backend/openapi/parser.js.map +1 -0
- package/dist/backend/types.d.ts +9 -0
- package/dist/backend/types.d.ts.map +1 -0
- package/dist/backend/types.js +2 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/config/loader.d.ts +12 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +178 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/profiles.d.ts +12 -0
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/profiles.js +34 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/schema.d.ts +2034 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +257 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/watcher.d.ts +11 -0
- package/dist/config/watcher.d.ts.map +1 -0
- package/dist/config/watcher.js +39 -0
- package/dist/config/watcher.js.map +1 -0
- package/dist/configure-agent/cli.d.ts +2 -0
- package/dist/configure-agent/cli.d.ts.map +1 -0
- package/dist/configure-agent/cli.js +390 -0
- package/dist/configure-agent/cli.js.map +1 -0
- package/dist/discover/cli.d.ts +2 -0
- package/dist/discover/cli.d.ts.map +1 -0
- package/dist/discover/cli.js +97 -0
- package/dist/discover/cli.js.map +1 -0
- package/dist/discover/index.d.ts +19 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +70 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/openapi.d.ts +9 -0
- package/dist/discover/openapi.d.ts.map +1 -0
- package/dist/discover/openapi.js +47 -0
- package/dist/discover/openapi.js.map +1 -0
- package/dist/discover/strategies/fig.d.ts +29 -0
- package/dist/discover/strategies/fig.d.ts.map +1 -0
- package/dist/discover/strategies/fig.js +82 -0
- package/dist/discover/strategies/fig.js.map +1 -0
- package/dist/discover/strategies/help-parser.d.ts +21 -0
- package/dist/discover/strategies/help-parser.d.ts.map +1 -0
- package/dist/discover/strategies/help-parser.js +121 -0
- package/dist/discover/strategies/help-parser.js.map +1 -0
- package/dist/discover/writer.d.ts +5 -0
- package/dist/discover/writer.d.ts.map +1 -0
- package/dist/discover/writer.js +14 -0
- package/dist/discover/writer.js.map +1 -0
- package/dist/gateway.d.ts +20 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +125 -0
- package/dist/gateway.js.map +1 -0
- package/dist/hitl/api.d.ts +7 -0
- package/dist/hitl/api.d.ts.map +1 -0
- package/dist/hitl/api.js +35 -0
- package/dist/hitl/api.js.map +1 -0
- package/dist/hitl/batcher.d.ts +11 -0
- package/dist/hitl/batcher.d.ts.map +1 -0
- package/dist/hitl/batcher.js +37 -0
- package/dist/hitl/batcher.js.map +1 -0
- package/dist/hitl/engine.d.ts +36 -0
- package/dist/hitl/engine.d.ts.map +1 -0
- package/dist/hitl/engine.js +150 -0
- package/dist/hitl/engine.js.map +1 -0
- package/dist/hitl/formatter.d.ts +4 -0
- package/dist/hitl/formatter.d.ts.map +1 -0
- package/dist/hitl/formatter.js +31 -0
- package/dist/hitl/formatter.js.map +1 -0
- package/dist/hitl/parser.d.ts +7 -0
- package/dist/hitl/parser.d.ts.map +1 -0
- package/dist/hitl/parser.js +17 -0
- package/dist/hitl/parser.js.map +1 -0
- package/dist/hitl/provider-factory.d.ts +4 -0
- package/dist/hitl/provider-factory.d.ts.map +1 -0
- package/dist/hitl/provider-factory.js +42 -0
- package/dist/hitl/provider-factory.js.map +1 -0
- package/dist/hitl/providers/composite.d.ts +9 -0
- package/dist/hitl/providers/composite.d.ts.map +1 -0
- package/dist/hitl/providers/composite.js +23 -0
- package/dist/hitl/providers/composite.js.map +1 -0
- package/dist/hitl/providers/dashboard.d.ts +17 -0
- package/dist/hitl/providers/dashboard.d.ts.map +1 -0
- package/dist/hitl/providers/dashboard.js +210 -0
- package/dist/hitl/providers/dashboard.js.map +1 -0
- package/dist/hitl/providers/macos.d.ts +10 -0
- package/dist/hitl/providers/macos.d.ts.map +1 -0
- package/dist/hitl/providers/macos.js +65 -0
- package/dist/hitl/providers/macos.js.map +1 -0
- package/dist/hitl/providers/openclaw.d.ts +21 -0
- package/dist/hitl/providers/openclaw.d.ts.map +1 -0
- package/dist/hitl/providers/openclaw.js +106 -0
- package/dist/hitl/providers/openclaw.js.map +1 -0
- package/dist/hitl/providers/slack.d.ts +12 -0
- package/dist/hitl/providers/slack.d.ts.map +1 -0
- package/dist/hitl/providers/slack.js +24 -0
- package/dist/hitl/providers/slack.js.map +1 -0
- package/dist/hitl/providers/stdio.d.ts +12 -0
- package/dist/hitl/providers/stdio.d.ts.map +1 -0
- package/dist/hitl/providers/stdio.js +41 -0
- package/dist/hitl/providers/stdio.js.map +1 -0
- package/dist/hitl/providers/telegram.d.ts +22 -0
- package/dist/hitl/providers/telegram.d.ts.map +1 -0
- package/dist/hitl/providers/telegram.js +87 -0
- package/dist/hitl/providers/telegram.js.map +1 -0
- package/dist/hitl/providers/tui.d.ts +16 -0
- package/dist/hitl/providers/tui.d.ts.map +1 -0
- package/dist/hitl/providers/tui.js +169 -0
- package/dist/hitl/providers/tui.js.map +1 -0
- package/dist/hitl/providers/types.d.ts +18 -0
- package/dist/hitl/providers/types.d.ts.map +1 -0
- package/dist/hitl/providers/types.js +2 -0
- package/dist/hitl/providers/types.js.map +1 -0
- package/dist/hitl/providers/webhook.d.ts +13 -0
- package/dist/hitl/providers/webhook.d.ts.map +1 -0
- package/dist/hitl/providers/webhook.js +27 -0
- package/dist/hitl/providers/webhook.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/chain-builder.d.ts +16 -0
- package/dist/middleware/chain-builder.d.ts.map +1 -0
- package/dist/middleware/chain-builder.js +139 -0
- package/dist/middleware/chain-builder.js.map +1 -0
- package/dist/middleware/compose.d.ts +3 -0
- package/dist/middleware/compose.d.ts.map +1 -0
- package/dist/middleware/compose.js +15 -0
- package/dist/middleware/compose.js.map +1 -0
- package/dist/middleware/core/allowlist.d.ts +3 -0
- package/dist/middleware/core/allowlist.d.ts.map +1 -0
- package/dist/middleware/core/allowlist.js +23 -0
- package/dist/middleware/core/allowlist.js.map +1 -0
- package/dist/middleware/core/exec-policy.d.ts +3 -0
- package/dist/middleware/core/exec-policy.d.ts.map +1 -0
- package/dist/middleware/core/exec-policy.js +30 -0
- package/dist/middleware/core/exec-policy.js.map +1 -0
- package/dist/middleware/core/execute.d.ts +3 -0
- package/dist/middleware/core/execute.d.ts.map +1 -0
- package/dist/middleware/core/execute.js +35 -0
- package/dist/middleware/core/execute.js.map +1 -0
- package/dist/middleware/core/hitl-gate.d.ts +3 -0
- package/dist/middleware/core/hitl-gate.d.ts.map +1 -0
- package/dist/middleware/core/hitl-gate.js +38 -0
- package/dist/middleware/core/hitl-gate.js.map +1 -0
- package/dist/middleware/core/rate-limiter.d.ts +10 -0
- package/dist/middleware/core/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/core/rate-limiter.js +32 -0
- package/dist/middleware/core/rate-limiter.js.map +1 -0
- package/dist/middleware/core/schema-validator.d.ts +3 -0
- package/dist/middleware/core/schema-validator.d.ts.map +1 -0
- package/dist/middleware/core/schema-validator.js +31 -0
- package/dist/middleware/core/schema-validator.js.map +1 -0
- package/dist/middleware/detectors/injection-detector.d.ts +12 -0
- package/dist/middleware/detectors/injection-detector.d.ts.map +1 -0
- package/dist/middleware/detectors/injection-detector.js +129 -0
- package/dist/middleware/detectors/injection-detector.js.map +1 -0
- package/dist/middleware/detectors/sensitivity-classifier.d.ts +12 -0
- package/dist/middleware/detectors/sensitivity-classifier.d.ts.map +1 -0
- package/dist/middleware/detectors/sensitivity-classifier.js +125 -0
- package/dist/middleware/detectors/sensitivity-classifier.js.map +1 -0
- package/dist/middleware/post/canary-token-injector.d.ts +10 -0
- package/dist/middleware/post/canary-token-injector.d.ts.map +1 -0
- package/dist/middleware/post/canary-token-injector.js +53 -0
- package/dist/middleware/post/canary-token-injector.js.map +1 -0
- package/dist/middleware/post/output-injection-detector.d.ts +7 -0
- package/dist/middleware/post/output-injection-detector.d.ts.map +1 -0
- package/dist/middleware/post/output-injection-detector.js +46 -0
- package/dist/middleware/post/output-injection-detector.js.map +1 -0
- package/dist/middleware/post/output-size-limiter.d.ts +7 -0
- package/dist/middleware/post/output-size-limiter.d.ts.map +1 -0
- package/dist/middleware/post/output-size-limiter.js +47 -0
- package/dist/middleware/post/output-size-limiter.js.map +1 -0
- package/dist/middleware/post/output-summarizer.d.ts +15 -0
- package/dist/middleware/post/output-summarizer.d.ts.map +1 -0
- package/dist/middleware/post/output-summarizer.js +38 -0
- package/dist/middleware/post/output-summarizer.js.map +1 -0
- package/dist/middleware/post/strip-query-params.d.ts +3 -0
- package/dist/middleware/post/strip-query-params.d.ts.map +1 -0
- package/dist/middleware/post/strip-query-params.js +22 -0
- package/dist/middleware/post/strip-query-params.js.map +1 -0
- package/dist/middleware/post/untrusted-envelope.d.ts +3 -0
- package/dist/middleware/post/untrusted-envelope.d.ts.map +1 -0
- package/dist/middleware/post/untrusted-envelope.js +10 -0
- package/dist/middleware/post/untrusted-envelope.js.map +1 -0
- package/dist/middleware/types.d.ts +32 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware/types.js +2 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/pool/http-client.d.ts +26 -0
- package/dist/pool/http-client.d.ts.map +1 -0
- package/dist/pool/http-client.js +109 -0
- package/dist/pool/http-client.js.map +1 -0
- package/dist/pool/oauth-provider.d.ts +34 -0
- package/dist/pool/oauth-provider.d.ts.map +1 -0
- package/dist/pool/oauth-provider.js +135 -0
- package/dist/pool/oauth-provider.js.map +1 -0
- package/dist/pool/pool.d.ts +30 -0
- package/dist/pool/pool.d.ts.map +1 -0
- package/dist/pool/pool.js +119 -0
- package/dist/pool/pool.js.map +1 -0
- package/dist/pool/required-mcps.d.ts +7 -0
- package/dist/pool/required-mcps.d.ts.map +1 -0
- package/dist/pool/required-mcps.js +18 -0
- package/dist/pool/required-mcps.js.map +1 -0
- package/dist/pool/sse-client.d.ts +22 -0
- package/dist/pool/sse-client.d.ts.map +1 -0
- package/dist/pool/sse-client.js +70 -0
- package/dist/pool/sse-client.js.map +1 -0
- package/dist/pool/stdio-client.d.ts +24 -0
- package/dist/pool/stdio-client.d.ts.map +1 -0
- package/dist/pool/stdio-client.js +77 -0
- package/dist/pool/stdio-client.js.map +1 -0
- package/dist/registry/registry.d.ts +19 -0
- package/dist/registry/registry.d.ts.map +1 -0
- package/dist/registry/registry.js +85 -0
- package/dist/registry/registry.js.map +1 -0
- package/dist/registry/sanitizer.d.ts +2 -0
- package/dist/registry/sanitizer.d.ts.map +1 -0
- package/dist/registry/sanitizer.js +31 -0
- package/dist/registry/sanitizer.js.map +1 -0
- package/dist/security/blocked-hosts.d.ts +6 -0
- package/dist/security/blocked-hosts.d.ts.map +1 -0
- package/dist/security/blocked-hosts.js +26 -0
- package/dist/security/blocked-hosts.js.map +1 -0
- package/dist/security/domain-allowlist.d.ts +7 -0
- package/dist/security/domain-allowlist.d.ts.map +1 -0
- package/dist/security/domain-allowlist.js +19 -0
- package/dist/security/domain-allowlist.js.map +1 -0
- package/dist/stdio-mode.d.ts +3 -0
- package/dist/stdio-mode.d.ts.map +1 -0
- package/dist/stdio-mode.js +130 -0
- package/dist/stdio-mode.js.map +1 -0
- package/dist/tools/exec.d.ts +20 -0
- package/dist/tools/exec.d.ts.map +1 -0
- package/dist/tools/exec.js +105 -0
- package/dist/tools/exec.js.map +1 -0
- package/dist/tools/http.d.ts +13 -0
- package/dist/tools/http.d.ts.map +1 -0
- package/dist/tools/http.js +99 -0
- package/dist/tools/http.js.map +1 -0
- package/dist/transport/agent-server.d.ts +26 -0
- package/dist/transport/agent-server.d.ts.map +1 -0
- package/dist/transport/agent-server.js +55 -0
- package/dist/transport/agent-server.js.map +1 -0
- package/dist/transport/mcp-normalizer.d.ts +9 -0
- package/dist/transport/mcp-normalizer.d.ts.map +1 -0
- package/dist/transport/mcp-normalizer.js +12 -0
- package/dist/transport/mcp-normalizer.js.map +1 -0
- package/dist/transport/sse-server.d.ts +7 -0
- package/dist/transport/sse-server.d.ts.map +1 -0
- package/dist/transport/sse-server.js +94 -0
- package/dist/transport/sse-server.js.map +1 -0
- package/dist/transport/stdio-server.d.ts +3 -0
- package/dist/transport/stdio-server.d.ts.map +1 -0
- package/dist/transport/stdio-server.js +12 -0
- package/dist/transport/stdio-server.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util/id.d.ts +5 -0
- package/dist/util/id.d.ts.map +1 -0
- package/dist/util/id.js +16 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/logger.d.ts +4 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +24 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/examples/claude-code-setup.md +77 -0
- package/examples/gateway.yaml +118 -0
- package/examples/local-dev.yaml +41 -0
- package/examples/openclaw-setup.md +52 -0
- package/examples/profiles.yaml +103 -0
- package/package.json +80 -3
- package/schema.json +943 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Airlock
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Airlock
|
|
2
|
+
|
|
3
|
+
[](https://github.com/airlock-dev/airlock/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/airlock-bot)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A permissions-aware MCP gateway that sits between AI agents (Claude Code, Cursor, OpenClaw, etc.) and your downstream tool servers, CLI tools, and REST APIs. Airlock enforces per-agent allowlists, requires human approval for sensitive operations, and keeps a full audit trail of every tool call.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Agent (Claude Code / Cursor / OpenClaw)
|
|
11
|
+
│ stdio or SSE
|
|
12
|
+
▼
|
|
13
|
+
Airlock ←→ HITL (Telegram / Slack / webhook / TUI / macOS / dashboard)
|
|
14
|
+
│
|
|
15
|
+
├── MCP servers (github, filesystem, ...)
|
|
16
|
+
├── CLI tools (git, docker, kubectl, ...)
|
|
17
|
+
├── REST APIs (any OpenAPI spec)
|
|
18
|
+
├── built-in: http/get, http/post, ...
|
|
19
|
+
└── built-in: exec/run
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Per-agent allowlists** — each agent sees only the tools it's allowed to call, presented with namespaced names (`github/create_pr`, `filesystem/read_file`)
|
|
25
|
+
- **HITL approval** — flag sensitive tools as requiring human sign-off; the agent blocks until you approve or deny
|
|
26
|
+
- **Composable profiles** — define reusable permission sets (`readonly`, `developer`) that agents inherit via `extends`
|
|
27
|
+
- **Backend adapters** — unified interface for MCP servers, CLI tools, REST APIs, HTTP, and exec
|
|
28
|
+
- **CLI tool discovery** — auto-generate config from `--help` output or [Fig autocomplete specs](https://github.com/withfig/autocomplete)
|
|
29
|
+
- **API discovery** — auto-generate config from OpenAPI 3.x specs
|
|
30
|
+
- **Configure agent TUI** — interactive terminal UI to assign allow/ask/deny per tool
|
|
31
|
+
- **Batched notifications** — requests arriving within a time window are bundled into a single message
|
|
32
|
+
- **Multiple HITL providers** — Telegram, Slack webhook, generic webhook, OpenClaw, TUI, macOS dialog, dashboard, or stdio
|
|
33
|
+
- **Security defaults** — localhost and RFC-1918 ranges blocked for HTTP tools; per-agent domain allowlists; shell injection prevention
|
|
34
|
+
- **Audit log** — every tool call logged to SQLite with agent, tool, args, result, duration, and HITL outcome
|
|
35
|
+
- **Hot reload** — edit config and allowlist/HITL config updates without restarting
|
|
36
|
+
- **Leaner stdio mode** — `--agent` flag runs with no HTTP server and only connects to MCPs the agent actually uses
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install -g airlock-bot
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick start
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# 1. Discover tools from a CLI you want to expose
|
|
48
|
+
airlock discover cli git --output git-commands.yaml
|
|
49
|
+
|
|
50
|
+
# 2. Create your config referencing the discovered commands
|
|
51
|
+
cat > airlock.yaml <<'EOF'
|
|
52
|
+
providers:
|
|
53
|
+
github:
|
|
54
|
+
type: stdio
|
|
55
|
+
command: npx
|
|
56
|
+
args: ["-y", "@modelcontextprotocol/server-github"]
|
|
57
|
+
env:
|
|
58
|
+
GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}"
|
|
59
|
+
exec: builtin
|
|
60
|
+
http: builtin
|
|
61
|
+
|
|
62
|
+
clis:
|
|
63
|
+
git:
|
|
64
|
+
discovered: ./git-commands.yaml
|
|
65
|
+
commands:
|
|
66
|
+
# Inline overrides take precedence over discovered commands
|
|
67
|
+
status:
|
|
68
|
+
exec: git status
|
|
69
|
+
params: {}
|
|
70
|
+
|
|
71
|
+
agents:
|
|
72
|
+
claude-code:
|
|
73
|
+
allow:
|
|
74
|
+
- github/*
|
|
75
|
+
- git/*
|
|
76
|
+
ask:
|
|
77
|
+
- git/push
|
|
78
|
+
deny:
|
|
79
|
+
- exec/run
|
|
80
|
+
EOF
|
|
81
|
+
|
|
82
|
+
# 3. Run in stdio mode for a single agent (e.g. from Claude Code)
|
|
83
|
+
airlock --agent claude-code --config airlock.yaml
|
|
84
|
+
|
|
85
|
+
# 4. Or run as a full gateway server (SSE on port 4111)
|
|
86
|
+
airlock --config airlock.yaml
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Claude Code setup
|
|
90
|
+
|
|
91
|
+
Add Airlock as an MCP server in `~/.claude/mcp.json`:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"airlock": {
|
|
97
|
+
"command": "airlock",
|
|
98
|
+
"args": ["--agent", "claude-code", "--config", "/path/to/airlock.yaml"]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or without a global install:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"airlock": {
|
|
110
|
+
"command": "npx",
|
|
111
|
+
"args": ["airlock-bot", "--agent", "claude-code", "--config", "/path/to/airlock.yaml"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
See [`examples/claude-code-setup.md`](examples/claude-code-setup.md) for a full walkthrough.
|
|
118
|
+
|
|
119
|
+
## Discovery
|
|
120
|
+
|
|
121
|
+
Auto-generate Airlock config from existing tools instead of writing YAML by hand.
|
|
122
|
+
|
|
123
|
+
### CLI discovery
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Parse --help output (works with any CLI)
|
|
127
|
+
airlock discover cli docker
|
|
128
|
+
|
|
129
|
+
# Try Fig autocomplete specs first, fall back to --help
|
|
130
|
+
airlock discover cli kubectl --fig
|
|
131
|
+
|
|
132
|
+
# Write to a file, limit recursion depth
|
|
133
|
+
airlock discover cli git --output git-commands.yaml --max-depth 2
|
|
134
|
+
|
|
135
|
+
# Only include specific commands
|
|
136
|
+
airlock discover cli npm --include install,test,run
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Reference the output in your config:
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
clis:
|
|
143
|
+
git:
|
|
144
|
+
discovered: ./git-commands.yaml
|
|
145
|
+
max_output_bytes: 30000 # default matches Claude Code's limit
|
|
146
|
+
commands:
|
|
147
|
+
# Inline commands override discovered ones with the same name
|
|
148
|
+
custom-deploy:
|
|
149
|
+
exec: "git push origin main"
|
|
150
|
+
params: {}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### API discovery
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# From a local spec file
|
|
157
|
+
airlock discover api ./petstore.json --output petstore-api.yaml
|
|
158
|
+
|
|
159
|
+
# From a URL
|
|
160
|
+
airlock discover api https://api.example.com/openapi.json --base-url https://api.example.com
|
|
161
|
+
|
|
162
|
+
# Filter endpoints
|
|
163
|
+
airlock discover api ./spec.json --include "GET *" --exclude "DELETE *"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Reference in config:
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
apis:
|
|
170
|
+
petstore:
|
|
171
|
+
spec: ./petstore.json
|
|
172
|
+
base_url: https://petstore.example.com/v1
|
|
173
|
+
auth:
|
|
174
|
+
type: bearer
|
|
175
|
+
token: ${PETSTORE_TOKEN}
|
|
176
|
+
timeout_ms: 30000
|
|
177
|
+
max_response_bytes: 1048576
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Configure agent TUI
|
|
181
|
+
|
|
182
|
+
Interactively assign allow/ask/deny to tools discovered from your live MCP servers:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npm run configure-agent -- --config ./airlock.yaml --agent claude-code
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Navigate with `j/k`, set permissions with `a`/`s`/`d` (per tool or bulk per provider), then `Enter` to edit config directly, copy to clipboard, or print YAML.
|
|
189
|
+
|
|
190
|
+
## Config
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
providers:
|
|
194
|
+
github:
|
|
195
|
+
type: stdio
|
|
196
|
+
command: npx
|
|
197
|
+
args: ["-y", "@modelcontextprotocol/server-github"]
|
|
198
|
+
env:
|
|
199
|
+
GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}"
|
|
200
|
+
|
|
201
|
+
exec: builtin
|
|
202
|
+
http: builtin
|
|
203
|
+
|
|
204
|
+
# CLI tools exposed as MCP tools
|
|
205
|
+
clis:
|
|
206
|
+
git:
|
|
207
|
+
discovered: ./git-commands.yaml
|
|
208
|
+
shell: /bin/bash
|
|
209
|
+
max_output_bytes: 30000
|
|
210
|
+
commands:
|
|
211
|
+
status:
|
|
212
|
+
exec: git status
|
|
213
|
+
params: {}
|
|
214
|
+
log:
|
|
215
|
+
exec: "git log --oneline -n {count}"
|
|
216
|
+
params:
|
|
217
|
+
count:
|
|
218
|
+
type: number
|
|
219
|
+
required: false
|
|
220
|
+
default: 10
|
|
221
|
+
|
|
222
|
+
# REST APIs exposed as MCP tools
|
|
223
|
+
apis:
|
|
224
|
+
petstore:
|
|
225
|
+
spec: ./petstore.json
|
|
226
|
+
base_url: https://petstore.example.com/v1
|
|
227
|
+
auth:
|
|
228
|
+
type: bearer
|
|
229
|
+
token: ${PETSTORE_TOKEN}
|
|
230
|
+
|
|
231
|
+
# Reusable permission profiles
|
|
232
|
+
profiles:
|
|
233
|
+
readonly:
|
|
234
|
+
allow:
|
|
235
|
+
- github/list*
|
|
236
|
+
- github/get*
|
|
237
|
+
- http/get
|
|
238
|
+
|
|
239
|
+
developer:
|
|
240
|
+
allow:
|
|
241
|
+
- github/*
|
|
242
|
+
- git/*
|
|
243
|
+
- exec/run
|
|
244
|
+
ask:
|
|
245
|
+
- github/create_pr
|
|
246
|
+
- github/merge_pull_request
|
|
247
|
+
|
|
248
|
+
agents:
|
|
249
|
+
helena:
|
|
250
|
+
extends: [readonly, developer]
|
|
251
|
+
exec:
|
|
252
|
+
allow: ["git status", "git diff*", "npm test*"]
|
|
253
|
+
ask: ["git push*"]
|
|
254
|
+
deny: ["sudo *", "rm -rf *"]
|
|
255
|
+
env:
|
|
256
|
+
PATH: "/usr/local/bin:/usr/bin:/bin"
|
|
257
|
+
http:
|
|
258
|
+
domain_allowlist: ["api.github.com", "*.sentry.io"]
|
|
259
|
+
|
|
260
|
+
claude-code:
|
|
261
|
+
extends: [readonly]
|
|
262
|
+
exec:
|
|
263
|
+
allow: ["git status", "git diff*", "npm test"]
|
|
264
|
+
deny: ["*"]
|
|
265
|
+
|
|
266
|
+
approvals:
|
|
267
|
+
provider:
|
|
268
|
+
type: telegram
|
|
269
|
+
bot_token: "${TELEGRAM_BOT_TOKEN}"
|
|
270
|
+
chat_id: "${TELEGRAM_CHAT_ID}"
|
|
271
|
+
timeout_ms: 300000
|
|
272
|
+
batch_window_ms: 10000
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Precedence: **deny > ask > allow > default-deny**
|
|
276
|
+
|
|
277
|
+
See [`examples/gateway.yaml`](examples/gateway.yaml) for a fully annotated reference config and [`examples/profiles.yaml`](examples/profiles.yaml) for composable profile examples.
|
|
278
|
+
|
|
279
|
+
## HITL providers
|
|
280
|
+
|
|
281
|
+
| Provider | Config `type` | Notes |
|
|
282
|
+
|----------|--------------|-------|
|
|
283
|
+
| TUI | `tui` | Terminal UI on stderr — `[a]pprove` / `[d]eny` with `j/k` navigation via `/dev/tty` |
|
|
284
|
+
| macOS dialog | `macos` | Native approve/deny popup via `osascript` — best for local dev on Mac |
|
|
285
|
+
| Dashboard | `dashboard` | Localhost web UI (default port 4112) with live SSE updates |
|
|
286
|
+
| Telegram bot | `telegram` | Long-polls for replies; reply `approve ABC123` or `deny ABC123` |
|
|
287
|
+
| Slack webhook | `slack` | Incoming webhook, fire-and-forget; pair with slash commands for approvals |
|
|
288
|
+
| Generic webhook | `webhook` | POSTs `{requests, text}` JSON; configurable headers |
|
|
289
|
+
| OpenClaw | `openclaw` | WebSocket RPC to OpenClaw gateway; see [`examples/openclaw-setup.md`](examples/openclaw-setup.md) |
|
|
290
|
+
| stdio | `stdio` | Prints to stderr, reads from stdin — for local dev and testing |
|
|
291
|
+
|
|
292
|
+
## API
|
|
293
|
+
|
|
294
|
+
When running in gateway mode, Airlock exposes a management API:
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
GET /health — MCP health, pending HITL count, uptime
|
|
298
|
+
GET /hitl/pending — list pending approval requests
|
|
299
|
+
POST /hitl/approve/:id — approve a request
|
|
300
|
+
POST /hitl/deny/:id — deny a request (body: {"reason": "..."})
|
|
301
|
+
GET /audit?agent=&tool=&since=&limit= — query audit log
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
All management endpoints require `Authorization: Bearer <api_secret>` when `server.api_secret` is set.
|
|
305
|
+
|
|
306
|
+
## Testing
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
npm test # unit + integration tests
|
|
310
|
+
npm test -- test/integration.test.ts # just the integration test (real child process)
|
|
311
|
+
npm run typecheck # TypeScript type check (no emit)
|
|
312
|
+
npm run build # Full build to dist/
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Interactive testing with MCP Inspector
|
|
316
|
+
|
|
317
|
+
A self-contained test config with an echo MCP server is included — no tokens or external services needed:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
npx @modelcontextprotocol/inspector npx tsx src/index.ts -- --agent test --config test/test-gateway.yaml
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Open `http://localhost:6274`, then list tools and call `echo/echo` or `echo/add` through the UI.
|
|
324
|
+
|
|
325
|
+
## systemd
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
sudo cp airlock.service /etc/systemd/system/
|
|
329
|
+
sudo systemctl daemon-reload
|
|
330
|
+
sudo systemctl enable --now airlock
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
See [`airlock.service`](airlock.service) for the full unit file.
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
[MIT](LICENSE) © 2026 Airlock
|
package/airlock.service
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=Airlock MCP Gateway
|
|
3
|
+
After=network.target openclaw-gateway.service
|
|
4
|
+
Wants=openclaw-gateway.service
|
|
5
|
+
|
|
6
|
+
[Service]
|
|
7
|
+
Type=simple
|
|
8
|
+
User=openclaw
|
|
9
|
+
WorkingDirectory=/home/openclaw/airlock
|
|
10
|
+
ExecStart=/usr/local/bin/airlock --config /etc/airlock/gateway.yaml
|
|
11
|
+
Restart=on-failure
|
|
12
|
+
RestartSec=5
|
|
13
|
+
StandardOutput=journal
|
|
14
|
+
StandardError=journal
|
|
15
|
+
SyslogIdentifier=airlock
|
|
16
|
+
|
|
17
|
+
# Environment
|
|
18
|
+
EnvironmentFile=-/etc/airlock/env
|
|
19
|
+
|
|
20
|
+
# Hardening
|
|
21
|
+
NoNewPrivileges=true
|
|
22
|
+
ProtectSystem=strict
|
|
23
|
+
ProtectHome=read-only
|
|
24
|
+
ReadWritePaths=/var/lib/airlock
|
|
25
|
+
|
|
26
|
+
[Install]
|
|
27
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentConfig } from '../config/schema.js';
|
|
2
|
+
export type Decision = 'allow' | 'ask' | 'deny';
|
|
3
|
+
export declare class AllowlistEngine {
|
|
4
|
+
private agents;
|
|
5
|
+
constructor(agents: Record<string, AgentConfig>);
|
|
6
|
+
reload(agents: Record<string, AgentConfig>): void;
|
|
7
|
+
evaluate(agentId: string, toolName: string): Decision;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/allowlist/engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAEvD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,IAAI;IAIjD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ;CAWtD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { matches } from './pattern.js';
|
|
2
|
+
export class AllowlistEngine {
|
|
3
|
+
agents;
|
|
4
|
+
constructor(agents) {
|
|
5
|
+
this.agents = agents;
|
|
6
|
+
}
|
|
7
|
+
reload(agents) {
|
|
8
|
+
this.agents = agents;
|
|
9
|
+
}
|
|
10
|
+
evaluate(agentId, toolName) {
|
|
11
|
+
const agent = this.agents[agentId];
|
|
12
|
+
if (!agent)
|
|
13
|
+
return 'deny';
|
|
14
|
+
// deny > ask > allow > default-deny
|
|
15
|
+
if (agent.deny.some((p) => matches(p, toolName)))
|
|
16
|
+
return 'deny';
|
|
17
|
+
if (agent.ask.some((p) => matches(p, toolName)))
|
|
18
|
+
return 'ask';
|
|
19
|
+
if (agent.allow.some((p) => matches(p, toolName)))
|
|
20
|
+
return 'allow';
|
|
21
|
+
return 'deny'; // fail-closed
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/allowlist/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAKvC,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,MAAmC;QAAnC,WAAM,GAAN,MAAM,CAA6B;IAAG,CAAC;IAE3D,MAAM,CAAC,MAAmC;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,QAAQ,CAAC,OAAe,EAAE,QAAgB;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,MAAM,CAAC;QAE1B,oCAAoC;QACpC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YAAE,OAAO,MAAM,CAAC;QAChE,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAC9D,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;QAElE,OAAO,MAAM,CAAC,CAAC,cAAc;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match a tool name against a pattern.
|
|
3
|
+
* Supports:
|
|
4
|
+
* - Exact match: "github/create_pr"
|
|
5
|
+
* - Wildcard suffix: "github/*" matches "github/create_pr" but NOT "github2/foo"
|
|
6
|
+
*/
|
|
7
|
+
export declare function matches(pattern: string, toolName: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Match a command string against a pattern.
|
|
10
|
+
* Supports glob-style prefix matching with '*'.
|
|
11
|
+
*/
|
|
12
|
+
export declare function matchesCommand(pattern: string, command: string): boolean;
|
|
13
|
+
//# sourceMappingURL=pattern.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../src/allowlist/pattern.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAelE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAMxE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match a tool name against a pattern.
|
|
3
|
+
* Supports:
|
|
4
|
+
* - Exact match: "github/create_pr"
|
|
5
|
+
* - Wildcard suffix: "github/*" matches "github/create_pr" but NOT "github2/foo"
|
|
6
|
+
*/
|
|
7
|
+
export function matches(pattern, toolName) {
|
|
8
|
+
if (pattern === toolName)
|
|
9
|
+
return true;
|
|
10
|
+
if (pattern.endsWith('/*')) {
|
|
11
|
+
const prefix = pattern.slice(0, -1); // "github/"
|
|
12
|
+
return toolName.startsWith(prefix) && !toolName.slice(prefix.length).includes('/');
|
|
13
|
+
}
|
|
14
|
+
if (pattern.endsWith('*')) {
|
|
15
|
+
// e.g. "git*" — simple prefix match, but must stay within same namespace
|
|
16
|
+
const prefix = pattern.slice(0, -1);
|
|
17
|
+
return toolName.startsWith(prefix);
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Match a command string against a pattern.
|
|
23
|
+
* Supports glob-style prefix matching with '*'.
|
|
24
|
+
*/
|
|
25
|
+
export function matchesCommand(pattern, command) {
|
|
26
|
+
if (pattern === command)
|
|
27
|
+
return true;
|
|
28
|
+
if (pattern.endsWith('*')) {
|
|
29
|
+
return command.startsWith(pattern.slice(0, -1));
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern.js","sourceRoot":"","sources":["../../src/allowlist/pattern.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,QAAgB;IACvD,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEtC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY;QACjD,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,yEAAyE;QACzE,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,OAAe;IAC7D,IAAI,OAAO,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { AuditLogger } from './logger.js';
|
|
3
|
+
export declare function auditApiPlugin(app: FastifyInstance, opts: {
|
|
4
|
+
auditLogger: AuditLogger;
|
|
5
|
+
secret?: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/audit/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAU/C,wBAAsB,cAAc,CAClC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'crypto';
|
|
2
|
+
function constantTimeEqual(a, b) {
|
|
3
|
+
const bufA = Buffer.from(a);
|
|
4
|
+
const bufB = Buffer.from(b);
|
|
5
|
+
if (bufA.length !== bufB.length)
|
|
6
|
+
return false;
|
|
7
|
+
return timingSafeEqual(bufA, bufB);
|
|
8
|
+
}
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
10
|
+
export async function auditApiPlugin(app, opts) {
|
|
11
|
+
const { auditLogger, secret } = opts;
|
|
12
|
+
app.addHook('preHandler', async (request, reply) => {
|
|
13
|
+
if (!secret)
|
|
14
|
+
return;
|
|
15
|
+
const auth = request.headers.authorization ?? '';
|
|
16
|
+
if (!constantTimeEqual(auth, `Bearer ${secret}`)) {
|
|
17
|
+
return reply.status(401).send({ error: 'Unauthorized' });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
app.get('/audit', async (request, reply) => {
|
|
21
|
+
const { agent, tool, since, limit } = request.query;
|
|
22
|
+
const entries = auditLogger.query({
|
|
23
|
+
agent,
|
|
24
|
+
tool,
|
|
25
|
+
since,
|
|
26
|
+
limit: limit ? parseInt(limit, 10) : 100,
|
|
27
|
+
});
|
|
28
|
+
return reply.send(entries);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/audit/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAIzC,SAAS,iBAAiB,CAAC,CAAS,EAAE,CAAS;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAoB,EACpB,IAAmD;IAEnD,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAErC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACjD,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,MAAM,EAAE,CAAC,EAAE,CAAC;YACjD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACzC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,KAA+B,CAAC;QAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC;YAChC,KAAK;YACL,IAAI;YACJ,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;SACzC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface AuditEntry {
|
|
2
|
+
id?: number;
|
|
3
|
+
ts: string;
|
|
4
|
+
agent_id: string;
|
|
5
|
+
tool: string;
|
|
6
|
+
args: string;
|
|
7
|
+
result: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
duration_ms?: number;
|
|
10
|
+
hitl_code?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface HitlQueueEntry {
|
|
13
|
+
id: string;
|
|
14
|
+
code: string;
|
|
15
|
+
agent_id: string;
|
|
16
|
+
tool: string;
|
|
17
|
+
args: string;
|
|
18
|
+
status: 'pending' | 'approved' | 'denied' | 'timeout';
|
|
19
|
+
reason?: string;
|
|
20
|
+
created_at: string;
|
|
21
|
+
resolved_at?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class AuditDb {
|
|
24
|
+
private db;
|
|
25
|
+
private stmts;
|
|
26
|
+
constructor(dbPath: string);
|
|
27
|
+
private init;
|
|
28
|
+
private prepareStatements;
|
|
29
|
+
insertAudit(entry: Omit<AuditEntry, 'id'>): void;
|
|
30
|
+
queryAudit(filters: {
|
|
31
|
+
agent?: string;
|
|
32
|
+
tool?: string;
|
|
33
|
+
since?: string;
|
|
34
|
+
limit?: number;
|
|
35
|
+
}): AuditEntry[];
|
|
36
|
+
insertHitl(entry: HitlQueueEntry): void;
|
|
37
|
+
updateHitlStatus(id: string, status: HitlQueueEntry['status'], reason?: string): void;
|
|
38
|
+
getHitlByCode(code: string): HitlQueueEntry | undefined;
|
|
39
|
+
getHitlById(id: string): HitlQueueEntry | undefined;
|
|
40
|
+
getPendingHitl(): HitlQueueEntry[];
|
|
41
|
+
cleanup(retentionDays: number): void;
|
|
42
|
+
close(): void;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/audit/db.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,KAAK,CASX;gBAEU,MAAM,EAAE,MAAM;IAM1B,OAAO,CAAC,IAAI;IAiCZ,OAAO,CAAC,iBAAiB;IAyBzB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,IAAI;IAShD,UAAU,CAAC,OAAO,EAAE;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,UAAU,EAAE;IA0BhB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAIvC,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IASrF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIvD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAInD,cAAc,IAAI,cAAc,EAAE;IAIlC,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAMpC,KAAK,IAAI,IAAI;CAGd"}
|