capgate 0.0.2 → 0.0.3

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 CHANGED
@@ -10,11 +10,9 @@ MCP servers today either run with full host trust (Claude Desktop, most wrappers
10
10
  manifest (JSON) → Capability[] → NormalizedPolicy → adapter (bwrap | docker) → argv + egress + env + assertions
11
11
  ```
12
12
 
13
- It is a compiler, not a runtime. It does not execute tools, resolve secrets, or speak MCP on the wire.
13
+ It is a **sandbox compiler for MCP servers**, not a runtime. It does not execute tools, resolve secrets, or speak MCP on the wire. Its job is to make the sandbox boundary **reviewable in a PR before the first agent call** — what the server is allowed to reach lives in the repo, not in someone's `docker run` muscle memory.
14
14
 
15
- **Validated against 10 real MCP servers** (filesystem, fetch, git, memory, time, github, postgres, sqlite, brave-search, puppeteer) — see [the inventory](tests/fixtures/policy/GO_NO_GO.md). 9/10 lower mechanically; the 10th (puppeteer) drove the `nestedSandbox` refinement.
16
-
17
- Status: **v0.0.2.** Two adapters (`bwrap`, `docker`) are golden-tested and ready to embed. Grammar may evolve through v0.1 based on design-partner feedback.
15
+ **For platform and security engineers** who can't ship MCP servers under blanket host trust and don't want to hand-write bwrap argv or `docker run` flags per server. **Not for** end-user agent UIs (this isn't a runtime), or for teams who want post-hoc tool-call auditing that's a different lane (see [How capgate compares](#how-capgate-compares) below for the short version, or [A working map of MCP security tools](https://razukc.github.io/capgate/positioning/) for the full discussion).
18
16
 
19
17
  ---
20
18
 
@@ -26,11 +24,45 @@ npm install capgate
26
24
 
27
25
  Requires Node.js ≥ 18.
28
26
 
29
- ## Example
27
+ ## 30-second example
28
+
29
+ ```ts
30
+ import { compile, lowerToDocker } from 'capgate';
31
+
32
+ const docker = lowerToDocker(compile({
33
+ name: 'my-server',
34
+ version: '0.1.0',
35
+ tools: [{ name: 'read_file', capabilities: ['fs:read:/workspace/**'] }],
36
+ }));
37
+
38
+ console.log(docker.argv.join(' '));
39
+ // → --rm --cap-drop ALL --security-opt no-new-privileges --read-only
40
+ // --tmpfs /tmp --network none --volume /workspace:/workspace:ro
41
+ ```
42
+
43
+ One capability in, one container policy out. No declared network → `--network none`. Read-only declared → `:ro` mount. No env declared → no env crosses the boundary. The CLI prints the same artifact for `bwrap`.
30
44
 
31
- Consider an MCP `github` server that an agent uses with a personal access token. The threat: a tool description carrying adversarial text triggers a request to attacker-controlled infrastructure, exfiltrating the PAT. A default container won't stop this — it inherits the host environment and reaches any host on the internet. capgate compiles the manifest into a policy that does.
45
+ ## CLI
32
46
 
33
- Three tools, three capability kinds, lowered to both adapters:
47
+ ```bash
48
+ capgate compile manifest.json --target bwrap --pretty
49
+ capgate compile manifest.json --target docker --pretty
50
+ capgate compile manifest.json --target egress --egress-target squid --pretty
51
+ capgate compile manifest.json --target egress --egress-target nftables --pretty
52
+ cat manifest.json | capgate compile - --target docker
53
+ ```
54
+
55
+ `--target egress` emits a static proxy config for a host-run proxy (`--egress-target squid|nftables`, default `squid`). Exits non-zero on parse errors (3), unknown arguments (2), or `CompilationError` (4). See `capgate --help`.
56
+
57
+ ---
58
+
59
+ ## Worked example: `github` server with PAT
60
+
61
+ The 30-second example is a single tool with a single capability. A realistic MCP server has several tools, several capability kinds, and a threat model that motivates the sandbox in the first place.
62
+
63
+ **The threat.** An MCP `github` server runs with a personal access token in its environment. A tool description carrying adversarial text triggers an outbound request to attacker-controlled infrastructure, exfiltrating the PAT. A default container won't stop this — it inherits the host environment and reaches any host on the internet.
64
+
65
+ **The verdict.** capgate compiles the manifest below into a policy whose egress allowlist contains exactly one entry: `api.github.com:443`. An egress proxy honoring that allowlist refuses any outbound request that isn't api.github.com, blocking PAT exfiltration to a third party. No host env is inherited; only `GITHUB_PERSONAL_ACCESS_TOKEN` is named for the host's secret store to inject at exec time.
34
66
 
35
67
  ```ts
36
68
  import { compile, lowerToBwrap, lowerToDocker } from 'capgate';
@@ -64,7 +96,6 @@ const manifest = {
64
96
  };
65
97
 
66
98
  const policy = compile(manifest);
67
-
68
99
  const bwrap = lowerToBwrap(policy);
69
100
  const docker = lowerToDocker(policy, { readOnlyRootfs: true });
70
101
 
@@ -76,14 +107,14 @@ const docker = lowerToDocker(policy, { readOnlyRootfs: true });
76
107
  // .notes — audit-friendly diagnostics (drift, edge cases, host decisions)
77
108
  ```
78
109
 
79
- The compiler unions per-tool capabilities into a server-level policy: `apply_patch` widens `/workspace` from `:ro` to `:rw`, and only one env name (`GITHUB_PERSONAL_ACCESS_TOKEN`) survives the merge. Both artifacts produce the same `egress` entry, which is the load-bearing line — an egress proxy honoring it refuses any outbound request that isn't `api.github.com:443`, blocking PAT exfiltration to a third party.
110
+ The compiler unions per-tool capabilities into a server-level policy: `apply_patch` widens `/workspace` from `:ro` to `:rw`, and only one env name survives the merge.
80
111
 
81
112
  ```jsonc
82
113
  // docker.egress === bwrap.egress
83
114
  [{ "host": "api.github.com", "port": 443, "blockPrivate": true }]
84
115
  ```
85
116
 
86
- The `argv` for each adapter (`docker` shown in full; `bwrap` abridged):
117
+ Adapter `argv` (docker shown in full; bwrap abridged):
87
118
 
88
119
  ```
89
120
  # docker (full)
@@ -102,34 +133,62 @@ The `argv` for each adapter (`docker` shown in full; `bwrap` abridged):
102
133
  --setenv HOME /tmp
103
134
  ```
104
135
 
105
- Note what's *missing* from the docker `argv`: no inherited host env, no host network, no extra capabilities, no writable rootfs. The `--env GITHUB_PERSONAL_ACCESS_TOKEN` line names the only secret that crosses the boundary; the host injects its value from a secret store at exec time. capgate emits the policy; enforcement is the host's job.
136
+ Note what's *missing* from the docker `argv`: no inherited host env, no host network, no extra capabilities, no writable rootfs. capgate emits the policy; enforcement is the host's job.
106
137
 
107
138
  Full golden outputs: [`bwrap/github.json`](tests/fixtures/policy/policies/bwrap/github.json), [`docker/github.json`](tests/fixtures/policy/policies/docker/github.json). Worked examples for `filesystem`, `fetch` (egress + assertions), and `puppeteer` (nested-sandbox edge case) live alongside them.
108
139
 
109
- ### CLI
140
+ ---
110
141
 
111
- ```bash
112
- capgate compile manifest.json --target bwrap --pretty
113
- capgate compile manifest.json --target docker --pretty
114
- cat manifest.json | capgate compile - --target docker
115
- ```
142
+ ## What's stable, what's evolving
143
+
144
+ `v0.0.x` is published for adopters who want to pin against capgate today. Stability commitments:
145
+
146
+ | Surface | Status in v0.0.x |
147
+ |---|---|
148
+ | Capability string grammar (`fs`, `net`, `env`, `assert` kinds) | **Stable.** String form will not change; new refinements are additive. |
149
+ | Adapter output shape (`argv`, `egress`, `envInjections`, `assertions`, `notes`) | **Stable.** Fields are additive; existing fields keep their semantics. |
150
+ | `compile()` and `lowerToBwrap` / `lowerToDocker` exports | **Stable.** |
151
+ | `lowerToEgress(policy, { target })` (`squid` / `nftables`) | **Usable.** Artifact shape (`config`, `filename`, `unenforceable`, `notes`) is additive; more `EgressTarget` values land without breaking existing ones. |
152
+ | `exec`, `ipc`, `clock` capability kinds | **Usable.** May gain refinements (like `exec:?nestedSandbox=true` did); existing forms keep working. |
153
+ | Adapter option objects (e.g. `lowerToDocker(policy, { readOnlyRootfs })`) | **Evolving.** Will expand in v0.1 as more adapters land. |
154
+ | `assert:` validator hook | **Metadata-only in v0.0.x.** Runtime hook lands in v0.2. |
155
+
156
+ Pin a minor range against `v0.0.x` for production review pipelines. Grammar additions land in `v0.1`; existing strings keep parsing.
116
157
 
117
- Exits non-zero on parse errors (3), unknown arguments (2), or `CompilationError` (4). See `capgate --help`.
158
+ ## How capgate compares
159
+
160
+ MCP-server security splits across three lanes. capgate is in the static-technical lane. The other two aren't competitors — most teams running MCP servers in production end up wanting more than one.
161
+
162
+ | Lane | What it does | When you'd use it |
163
+ |---|---|---|
164
+ | **Static technical** (capgate) | Reads a manifest, emits sandbox argv + egress allowlist. Static artifact, no runtime. | You want the sandbox policy reviewable in PR before the server ever runs. |
165
+ | **Static governance** | Reads a manifest, emits a compliance report against a threat catalog or policy framework. | You want a procedural sign-off on a server before it's adopted. |
166
+ | **Dynamic attestation** | Logs and cryptographically signs each tool call at runtime. | You need a tamper-evident record of what the server actually did. |
167
+
168
+ Two adjacent concerns are *not* on this map: per-request authentication (gateways / OAuth — about *who* is calling) and runtime threat detection (pattern-watching, anomaly alerts — about flagging in real time). Both are real categories; both are different conversations. See [A working map of MCP security tools](https://razukc.github.io/capgate/positioning/) for the full discussion.
169
+
170
+ If you arrived here from a comparison post and you wanted dynamic attestation or static governance, capgate isn't that — but the artifact it emits can be the input to either.
118
171
 
119
172
  ---
120
173
 
121
- ## Scope for v0.1
174
+ ## Validated servers
122
175
 
123
- **In scope:**
124
- - Capability grammar covering `fs`, `net`, `exec`, `env`, `ipc`, `clock`, `assert`.
125
- - Lowering to three targets: `bwrap` (Linux namespace sandbox), egress-proxy rules (net allowlist), Worker `resourceLimits` (in-process JS isolation).
126
- - Golden-file tests from real MCP server manifests.
176
+ Before committing to the capability-grammar abstraction, we ran a [go/no-go exercise](tests/fixtures/policy/GO_NO_GO.md) against 10 real MCP servers. The full inventory (capability strings, source links, lowering notes) lives in [`GO_NO_GO.md`](tests/fixtures/policy/GO_NO_GO.md); the summary:
127
177
 
128
- **Out of scope (deferred):**
129
- - Firecracker / microVM adapter — needed for production but not for proving the abstraction.
130
- - E2B / Daytona / Blaxel adapters API stability varies; wait for a design partner.
131
- - seccomp-bpf syscall filters requires a separate IR; out of the capability model.
132
- - MCP client/server implementation this library consumes manifests, it does not speak MCP on the wire.
178
+ | Server | Capabilities (excerpt) | Status | Manifest | bwrap | docker |
179
+ |---|---|---|---|---|---|
180
+ | [filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) | `fs:read,write:<roots>` | mechanical | [filesystem.json](tests/fixtures/policy/manifests/filesystem.json) | [✓](tests/fixtures/policy/policies/bwrap/filesystem.json) | [✓](tests/fixtures/policy/policies/docker/filesystem.json) |
181
+ | [fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch) | `net:connect:*`, `assert:fetch.block_rfc1918` | mechanical (assert) | [fetch.json](tests/fixtures/policy/manifests/fetch.json) | [✓](tests/fixtures/policy/policies/bwrap/fetch.json) | [✓](tests/fixtures/policy/policies/docker/fetch.json) |
182
+ | [git](https://github.com/modelcontextprotocol/servers/tree/main/src/git) | `fs:read,write:<repo>`, `exec:spawn:git`, `net:connect:*` | mechanical | | | |
183
+ | [memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory) | `fs:read,write:$MEMORY_FILE_PATH` | mechanical | — | — | — |
184
+ | [time](https://github.com/modelcontextprotocol/servers/tree/main/src/time) | `fs:read:/usr/share/zoneinfo`, `clock:tzdata` | mechanical | — | — | — |
185
+ | [github](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/github) | `net:connect:api.github.com:443`, `env:inject:GITHUB_PERSONAL_ACCESS_TOKEN` | mechanical | [github.json](tests/fixtures/policy/manifests/github.json) | [✓](tests/fixtures/policy/policies/bwrap/github.json) | [✓](tests/fixtures/policy/policies/docker/github.json) |
186
+ | [postgres](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/postgres) | `net:connect:<db>:<port>`, `assert:postgres.read_only_txn` | mechanical (assert) | — | — | — |
187
+ | [sqlite](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/sqlite) | `fs:read,write:<db_path>` | mechanical | — | — | — |
188
+ | [brave-search](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/brave-search) | `net:connect:api.search.brave.com:443`, `env:inject:BRAVE_API_KEY` | mechanical | — | — | — |
189
+ | [puppeteer](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/puppeteer) | `exec:spawn:chromium?nestedSandbox=true`, `ipc:connect:x11` | nested-sandbox | [puppeteer.json](tests/fixtures/policy/manifests/puppeteer.json) | [✓](tests/fixtures/policy/policies/bwrap/puppeteer.json) | [✓](tests/fixtures/policy/policies/docker/puppeteer.json) |
190
+
191
+ Four of the ten ship as golden-file fixtures for both adapters; the rest follow one of the four shapes and are tracked in `GO_NO_GO.md` for the next grammar review. **MCP server author?** If your server isn't listed and you'd like a fixture review, [open an issue](https://github.com/razukc/capgate/issues/new) with a link to the manifest.
133
192
 
134
193
  ## Capability grammar
135
194
 
@@ -150,6 +209,19 @@ assert:postgres.read_only_txn:"all queries run in READ ONLY TRANSACTION"
150
209
 
151
210
  The grammar rejects ambiguity (relative paths, bad ports, non-UPPER_SNAKE env vars) at parse time — fail-closed, always.
152
211
 
212
+ ## Scope for v0.1
213
+
214
+ **In scope:**
215
+ - Capability grammar covering `fs`, `net`, `exec`, `env`, `ipc`, `clock`, `assert`.
216
+ - Lowering to `bwrap` (Linux namespace sandbox), `docker` (`docker run` argv), and `egress` (proxy config — `squid` / `nftables`, **shipped**). Worker `resourceLimits` (in-process JS isolation) is the next target.
217
+ - Golden-file tests from real MCP server manifests.
218
+
219
+ **Out of scope (deferred):**
220
+ - Firecracker / microVM adapter — needed for production but not for proving the abstraction.
221
+ - E2B / Daytona / Blaxel adapters — API stability varies; wait for a design partner.
222
+ - seccomp-bpf syscall filters — requires a separate IR; out of the capability model.
223
+ - MCP client/server implementation — this library consumes manifests, it does not speak MCP on the wire.
224
+
153
225
  ## Design notes
154
226
 
155
227
  ### Why capabilities are typed and discriminated
@@ -168,6 +240,12 @@ JSON-object capabilities are verbose and bury the kind under keys. The string fo
168
240
 
169
241
  Chromium carries its own sandbox that fights namespace isolation. Every production sandbox tool has a special case for this. Rather than a new capability kind, `nestedSandbox=true` is a refinement on an existing `exec:` capability — the adapter sees it during lowering and emits a different bwrap profile (user/pid/ipc namespaces kept for inner-sandbox compatibility). The IR stays small; the edge case is explicit and documented.
170
242
 
243
+ ### Why egress lowers to a proxy config, not a proxy
244
+
245
+ `egress[]` is emitted by the bwrap and docker adapters but enforced by neither — the host is told to wire a proxy. The neither-adapter-can-actually-do-net property is real: bwrap's `--unshare-net` is all-or-nothing (it always isolates now; see the net posture in `bwrap.ts`), and Docker's default bridge NATs but doesn't allowlist. Closing that gap by *running* a proxy would turn capgate into a gateway and drag a long-running, root-adjacent process into a library whose whole value is being a static compiler.
246
+
247
+ The move keeps capgate a compiler: a third lowering target, `lowerToEgress(policy, { target })`, compiles `policy.net` into a config blob for a proxy the host *already runs* — `squid` (allowlist by hostname via CONNECT, no TLS interception) and `nftables` (allowlist by IP+port in-kernel, bypass-proof, plus the `blockPrivate` drops) ship today. Both configs are fail-closed: squid ends in an unconditional `http_access deny all`, nftables defaults to `policy drop`, and an empty `policy.net` compiles to a deny-ALL config. The artifact carries an `unenforceable[]` field naming every declared rule the chosen target *cannot* honor (e.g. nftables can't express `api.github.com` — it filters IPs, not rotating hostnames), so "portable" stays honest: it compiles everywhere and tells you what each backend loses. Envoy/Cloudflare/microVM targets are later entries behind the same `EgressTarget` switch; the IR does not change. This keeps Docker MCP Gateway and Cloudflare as *targets you compile to*, not competitors — the manifest stays the single reviewable source of truth, and enforcement is borrowed, not built.
248
+
171
249
  ## Non-goals that matter
172
250
 
173
251
  - **The compiler does not decide trust.** Capability declarations come from the manifest; the compiler does not infer them from tool descriptions. Inference belongs in a separate auditing tool. A manifest that under-declares is a bug in the manifest.
@@ -182,25 +260,6 @@ Chromium carries its own sandbox that fights namespace isolation. Every producti
182
260
 
183
261
  All compilation errors are fatal. There is no warning mode.
184
262
 
185
- ## Validated servers
186
-
187
- Before committing to the capability-grammar abstraction, we ran a [go/no-go exercise](tests/fixtures/policy/GO_NO_GO.md) against 10 real MCP servers. The full inventory (capability strings, source links, lowering notes) lives in [`GO_NO_GO.md`](tests/fixtures/policy/GO_NO_GO.md); the summary:
188
-
189
- | Server | Capabilities (excerpt) | Status | Manifest | bwrap | docker |
190
- |---|---|---|---|---|---|
191
- | [filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) | `fs:read,write:<roots>` | mechanical | [filesystem.json](tests/fixtures/policy/manifests/filesystem.json) | [✓](tests/fixtures/policy/policies/bwrap/filesystem.json) | [✓](tests/fixtures/policy/policies/docker/filesystem.json) |
192
- | [fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch) | `net:connect:*`, `assert:fetch.block_rfc1918` | mechanical (assert) | [fetch.json](tests/fixtures/policy/manifests/fetch.json) | [✓](tests/fixtures/policy/policies/bwrap/fetch.json) | [✓](tests/fixtures/policy/policies/docker/fetch.json) |
193
- | [git](https://github.com/modelcontextprotocol/servers/tree/main/src/git) | `fs:read,write:<repo>`, `exec:spawn:git`, `net:connect:*` | mechanical | — | — | — |
194
- | [memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory) | `fs:read,write:$MEMORY_FILE_PATH` | mechanical | — | — | — |
195
- | [time](https://github.com/modelcontextprotocol/servers/tree/main/src/time) | `fs:read:/usr/share/zoneinfo`, `clock:tzdata` | mechanical | — | — | — |
196
- | [github](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/github) | `net:connect:api.github.com:443`, `env:inject:GITHUB_PERSONAL_ACCESS_TOKEN` | mechanical | — | — | — |
197
- | [postgres](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/postgres) | `net:connect:<db>:<port>`, `assert:postgres.read_only_txn` | mechanical (assert) | — | — | — |
198
- | [sqlite](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/sqlite) | `fs:read,write:<db_path>` | mechanical | — | — | — |
199
- | [brave-search](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/brave-search) | `net:connect:api.search.brave.com:443`, `env:inject:BRAVE_API_KEY` | mechanical | — | — | — |
200
- | [puppeteer](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/puppeteer) | `exec:spawn:chromium?nestedSandbox=true`, `ipc:connect:x11` | nested-sandbox | [puppeteer.json](tests/fixtures/policy/manifests/puppeteer.json) | [✓](tests/fixtures/policy/policies/bwrap/puppeteer.json) | [✓](tests/fixtures/policy/policies/docker/puppeteer.json) |
201
-
202
- Three of the ten ship as golden-file fixtures for both adapters (representatives of the distinct shapes — pure-fs, net+assert, nested-sandbox); the remaining seven follow the filesystem or github shape and are tracked in `GO_NO_GO.md` for the next grammar review. **MCP server author?** If your server isn't listed and you'd like a fixture review, [open an issue](https://github.com/razukc/capgate/issues/new) with a link to the manifest.
203
-
204
263
  ## Test strategy
205
264
 
206
265
  Golden files. One fixture manifest → one expected policy per adapter. Every PR that changes grammar, IR, or an adapter must update the golden files in the same commit. Reviewers read the diff. This is the primary correctness mechanism; unit tests on the grammar are secondary.
@@ -212,16 +271,16 @@ npm run test:update-goldens # regenerate golden files after intentional change
212
271
 
213
272
  ## Open questions before v0.1
214
273
 
215
- 1. **Egress proxy choice.** mitmproxy (great DX, slow, not prod-grade) vs nftables (hard to author, prod-grade, Linux-only) vs Envoy (prod-grade, ops-heavy). Current plan: ship a thin YAML spec the compiler emits, plus one reference binding to mitmproxy for dev. Let ops pick their own enforcement.
274
+ 1. **Egress proxy choice.** mitmproxy (great DX, slow, not prod-grade) vs nftables (hard to author, prod-grade, Linux-only) vs Envoy (prod-grade, ops-heavy). Direction settled: capgate stays a compiler and emits a config blob per target rather than running a proxy — see [Why egress lowers to a proxy config, not a proxy](#why-egress-lowers-to-a-proxy-config-not-a-proxy). Both `squid` and `nftables` now ship as reference bindings (they cover complementary cases — hostname-CONNECT vs in-kernel IP allowlist). Remaining sub-question is whether a dev-only mitmproxy emitter is worth carrying.
216
275
  2. **Path glob semantics.** bwrap binds directories, not globs. A `fs:read:/workspace/**` capability lowers to `--ro-bind /workspace /workspace`, which is a *superset* of the declared scope. Runtime enforcement of globs is an MCP-server concern.
217
276
  3. **Server-level vs tool-level capabilities.** v0.0 unions them. Finer-grained per-tool sandboxing (one sandbox per invocation) is possible but expensive — deferred until a user asks for it.
218
277
 
219
278
  ## Contributing
220
279
 
221
- Design-partner stage. **Actively seeking feedback from teams reviewing MCP servers today** — please see [issue #1](https://github.com/razukc/capgate/issues/1) and share how your review process works (as much or as little as you can publicly). That is the single most valuable contribution right now.
222
-
223
280
  If you have a concrete manifest + unexpected compiler output, file an issue with both. See [CONTRIBUTING.md](CONTRIBUTING.md) for what else is useful.
224
281
 
282
+ Design-partner stage: if you're already reviewing MCP servers in production and willing to share how your review process works, [issue #1](https://github.com/razukc/capgate/issues/1) has a question for you.
283
+
225
284
  ## Security
226
285
 
227
286
  capgate compiles declarations into sandbox policies downstream hosts trust — bugs here can silently over-grant. Please report privately per [SECURITY.md](SECURITY.md).
package/dist/cli.js CHANGED
@@ -10,12 +10,13 @@
10
10
  // This is deliberately minimal. Anything fancier (watch mode, multi-target,
11
11
  // YAML output) belongs behind a feature flag, not here.
12
12
  import { readFileSync } from 'node:fs';
13
- import { compile, lowerToBwrap, lowerToDocker, CompilationError } from './policy/index.js';
13
+ import { compile, lowerToBwrap, lowerToDocker, lowerToEgress, CompilationError } from './policy/index.js';
14
14
  function parseArgs(argv) {
15
15
  const args = {
16
16
  command: undefined,
17
17
  input: undefined,
18
18
  target: 'bwrap',
19
+ egressTarget: 'squid',
19
20
  pretty: false,
20
21
  help: false,
21
22
  };
@@ -28,6 +29,8 @@ function parseArgs(argv) {
28
29
  args.pretty = true;
29
30
  else if (a === '--target')
30
31
  args.target = rest[++i];
32
+ else if (a === '--egress-target')
33
+ args.egressTarget = rest[++i];
31
34
  else if (!args.command)
32
35
  args.command = a;
33
36
  else if (!args.input)
@@ -41,13 +44,15 @@ Usage:
41
44
  capgate compile <manifest.json|-> [--target bwrap] [--pretty]
42
45
 
43
46
  Options:
44
- --target <name> Adapter to lower to. Default: bwrap. Supported: bwrap, docker.
45
- --pretty Indent JSON output with 2 spaces.
46
- -h, --help Show this message.
47
+ --target <name> Adapter to lower to. Default: bwrap. Supported: bwrap, docker, egress.
48
+ --egress-target <name> Egress backend when --target egress. Default: squid. Supported: squid, nftables.
49
+ --pretty Indent JSON output with 2 spaces.
50
+ -h, --help Show this message.
47
51
 
48
52
  Examples:
49
53
  capgate compile manifests/filesystem.json --pretty
50
54
  cat manifest.json | capgate compile - --target bwrap
55
+ capgate compile manifests/github.json --target egress --egress-target nftables --pretty
51
56
  `;
52
57
  function readInput(path) {
53
58
  if (path === '-')
@@ -86,8 +91,15 @@ function main() {
86
91
  case 'docker':
87
92
  output = lowerToDocker(policy);
88
93
  break;
94
+ case 'egress':
95
+ if (args.egressTarget !== 'squid' && args.egressTarget !== 'nftables') {
96
+ process.stderr.write(`capgate: unsupported --egress-target "${args.egressTarget}" (supported: squid, nftables)\n`);
97
+ process.exit(2);
98
+ }
99
+ output = lowerToEgress(policy, { target: args.egressTarget });
100
+ break;
89
101
  default:
90
- process.stderr.write(`capgate: unsupported --target "${args.target}" (supported: bwrap, docker)\n`);
102
+ process.stderr.write(`capgate: unsupported --target "${args.target}" (supported: bwrap, docker, egress)\n`);
91
103
  process.exit(2);
92
104
  }
93
105
  const indent = args.pretty ? 2 : 0;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,wDAAwD;AACxD,EAAE;AACF,SAAS;AACT,gEAAgE;AAChE,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,wDAAwD;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAY1G,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAS;QACjB,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,OAAO;QACf,YAAY,EAAE,OAAO;QACrB,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,KAAK;KACZ,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;aAC9C,IAAI,CAAC,KAAK,UAAU;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;aACzC,IAAI,CAAC,KAAK,UAAU;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC9C,IAAI,CAAC,KAAK,iBAAiB;YAAE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC3D,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;aACpC,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;CAeb,CAAC;AAEF,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,IAAI,KAAK,GAAG;QAAE,OAAO,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,IAAI,CAAC,OAAO,QAAQ,KAAK,EAAE,CAAC,CAAC;QAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mEAAmE,KAAK,EAAE,CAAC,CAAC;QACjG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA+C,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,GAAoC,CAAC,CAAC;QAC7D,IAAI,MAAe,CAAC;QACpB,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACpB,KAAK,OAAO;gBACV,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;gBAC9B,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,IAAI,CAAC,YAAY,KAAK,OAAO,IAAI,IAAI,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;oBACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yCAAyC,IAAI,CAAC,YAAY,kCAAkC,CAC7F,CAAC;oBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBACD,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,YAA4B,EAAE,CAAC,CAAC;gBAC9E,MAAM;YACR;gBACE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,IAAI,CAAC,MAAM,wCAAwC,CAAC,CAAC;gBAC5G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;YACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"bwrap.d.ts","sourceRoot":"","sources":["../../../src/policy/adapters/bwrap.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,0FAA0F;IAC1F,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,oDAAoD;IACpD,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,6DAA6D;IAC7D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,GAAE,YAAiB,GAAG,aAAa,CAoH7F"}
1
+ {"version":3,"file":"bwrap.d.ts","sourceRoot":"","sources":["../../../src/policy/adapters/bwrap.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,0FAA0F;IAC1F,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,oDAAoD;IACpD,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,6DAA6D;IAC7D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,GAAE,YAAiB,GAAG,aAAa,CAwH7F"}
@@ -10,6 +10,18 @@
10
10
  // - seccomp syscall filters → out of scope for v0.1
11
11
  // - secret value resolution → caller pulls from secret store
12
12
  //
13
+ // Net posture (fail-closed). bwrap's --unshare-net is all-or-nothing: an
14
+ // unprivileged user namespace cannot mint veth pairs or routes, so bwrap can
15
+ // only fully isolate the net namespace or fully share the host's. Selective
16
+ // egress is impossible inside bwrap alone. Therefore this adapter ALWAYS emits
17
+ // --unshare-net — even when egress is declared — and NEVER shares the host
18
+ // netns. A declared net capability does not relax isolation; it only records an
19
+ // EgressRule[] that a privileged broker must honor by launching the bwrap
20
+ // process inside a pre-created, egress-constrained network namespace. If no
21
+ // such broker exists, the sandbox simply has no network: deny-by-default holds.
22
+ // (The prior behavior — sharing host netns whenever net>0 — was a silent
23
+ // privilege escalation that read as a constraint; it is refused by design.)
24
+ //
13
25
  // This adapter emits a BwrapArtifact: argv for bwrap itself plus companion
14
26
  // data the host must honor. The host decides how to wire EgressRule — mitmproxy,
15
27
  // nftables, Envoy; the adapter stays policy-layer only.
@@ -20,14 +32,14 @@ export function lowerToBwrap(policy, opts = {}) {
20
32
  const systemMounts = opts.systemMounts ?? DEFAULT_SYSTEM_MOUNTS;
21
33
  const exposeDev = opts.exposeDev ?? policy.nestedSandbox;
22
34
  // ---------- base namespaces ----------
23
- // We build the unshare set explicitly instead of using --unshare-all so the
24
- // net flag is a single decision point. Net is only shared when policy.net
25
- // is non-empty; nestedSandbox additionally keeps user/pid/ipc for inner
26
- // sandboxes (Chromium, QEMU) that re-namespace themselves.
27
- const shareNet = policy.net.length > 0;
28
- argv.push('--unshare-uts', '--unshare-cgroup-try');
29
- if (!shareNet)
30
- argv.push('--unshare-net');
35
+ // We build the unshare set explicitly instead of using --unshare-all so each
36
+ // namespace is an auditable decision point. Net is ALWAYS unshared: bwrap
37
+ // cannot do selective egress (see header), so sharing the host netns would be
38
+ // a silent grant of full host network access. Declared egress is carried in
39
+ // egress[] for an external netns broker to enforce, never by relaxing this.
40
+ // nestedSandbox additionally keeps user/pid/ipc for inner sandboxes
41
+ // (Chromium, QEMU) that re-namespace themselves.
42
+ argv.push('--unshare-uts', '--unshare-cgroup-try', '--unshare-net');
31
43
  if (!policy.nestedSandbox) {
32
44
  argv.push('--unshare-user-try', '--unshare-pid', '--unshare-ipc');
33
45
  }
@@ -106,15 +118,18 @@ export function lowerToBwrap(policy, opts = {}) {
106
118
  argv.push('--setenv', 'HOME', '/tmp');
107
119
  // Values for envInjections are injected by the caller via --setenv at exec time.
108
120
  // ---------- net ----------
109
- // bwrap has only binary share/unshare. Host-level allowlists live in the
110
- // egress proxy. We emit rules either way so a deny-all proxy is a valid host.
121
+ // The net namespace is already unshared above, so the sandbox starts with NO
122
+ // network (loopback only). bwrap cannot open a constrained hole, so declared
123
+ // egress is NOT enforced here: we emit EgressRule[] for a privileged broker
124
+ // that runs this bwrap process inside a pre-created, egress-aware netns. We
125
+ // emit rules even for the empty case so a deny-all broker is a valid host.
111
126
  const egress = policy.net.map((n) => ({
112
127
  host: n.host,
113
128
  port: n.port,
114
129
  blockPrivate: n.blockPrivate,
115
130
  }));
116
131
  if (policy.net.length > 0) {
117
- notes.push(`net: ${policy.net.length} endpoint(s) declared — host MUST route outbound traffic through an egress proxy honoring egress[]`);
132
+ notes.push(`net: ${policy.net.length} endpoint(s) declared but NOT enforced by bwrap alone bwrap always unshares the net namespace (no host network). To grant egress, a privileged broker MUST launch bwrap inside a pre-created network namespace whose egress honors egress[]. Absent that broker the sandbox has no network. Sharing the host netns is refused by design.`);
118
133
  }
119
134
  return {
120
135
  argv,
@@ -1 +1 @@
1
- {"version":3,"file":"bwrap.js","sourceRoot":"","sources":["../../../src/policy/adapters/bwrap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bwrap.js","sourceRoot":"","sources":["../../../src/policy/adapters/bwrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { NormalizedPolicy } from '../ir.js';
2
+ import type { EgressRule } from './bwrap.js';
3
+ export type EgressTarget = 'squid' | 'nftables';
4
+ export interface EgressArtifact {
5
+ /** Which backend this config targets. */
6
+ target: EgressTarget;
7
+ /** The config file contents, ready to write to disk and load into the proxy. */
8
+ config: string;
9
+ /** Suggested filename, e.g. "capgate-egress.squid.conf". */
10
+ filename: string;
11
+ /** Declared rules this target CANNOT honor — surfaced, never silently dropped. */
12
+ unenforceable: {
13
+ rule: EgressRule;
14
+ reason: string;
15
+ }[];
16
+ /** Human-readable diagnostics for audit logs / PR review. */
17
+ notes: string[];
18
+ }
19
+ export interface EgressOptions {
20
+ /** Required — no default. The caller must pick the backend the host runs. */
21
+ target: EgressTarget;
22
+ }
23
+ export declare function lowerToEgress(policy: NormalizedPolicy, opts: EgressOptions): EgressArtifact;
24
+ //# sourceMappingURL=egress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.d.ts","sourceRoot":"","sources":["../../../src/policy/adapters/egress.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,aAAa,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtD,6DAA6D;IAC7D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,MAAM,EAAE,YAAY,CAAC;CACtB;AAQD,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,GAAG,cAAc,CAe3F"}
@@ -0,0 +1,194 @@
1
+ // Egress adapter: NormalizedPolicy → static proxy config blob.
2
+ //
3
+ // This is the third lowering lane (see README "Why egress will lower to a proxy
4
+ // config, not a proxy"). bwrap and docker emit argv; this adapter emits a config
5
+ // *file* for a proxy the HOST already runs. Same compiler-not-runtime contract:
6
+ // capgate compiles policy.net (+ blockPrivate) into a config, and the host wires
7
+ // it into squid / nftables. We never open a socket.
8
+ //
9
+ // What this lane handles:
10
+ // - squid: allowlist by hostname via CONNECT (no TLS interception)
11
+ // - nftables: allowlist by IP+port in-kernel (bypass-proof) + blockPrivate drops
12
+ // - the blockPrivate RFC1918/loopback deny that bwrap/docker can only assert
13
+ //
14
+ // What this lane does NOT handle:
15
+ // - RUNNING the proxy — the host owns the long-lived process; we emit a file.
16
+ // - DNS resolution — nftables filters IPs, not names; hostname rules that it
17
+ // cannot express are surfaced in unenforceable[], never silently dropped.
18
+ // - TLS interception / secret inspection — out of scope for v0.1. squid here
19
+ // is CONNECT-allowlist only; it sees SNI/host, never plaintext.
20
+ //
21
+ // Net posture (fail-closed). Every emitted config terminates or defaults in
22
+ // deny/drop: squid ends in an unconditional `http_access deny all`, nftables
23
+ // sets `policy drop`. No code path produces an allow-all config. An empty
24
+ // policy.net compiles to a deny-ALL config — mirroring how bwrap/docker treat
25
+ // net==0 (`--unshare-net` / `--network none`): declaring nothing grants nothing.
26
+ // Private-range destinations the blockPrivate flag must deny. Kept as two lists
27
+ // because squid and nftables spell them differently (squid uses one `dst` acl
28
+ // covering both families; nftables splits ip / ip6 daddr sets).
29
+ const PRIVATE_V4 = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '127.0.0.0/8', '169.254.0.0/16'];
30
+ const PRIVATE_V6 = ['::1/128', 'fc00::/7', 'fe80::/10'];
31
+ export function lowerToEgress(policy, opts) {
32
+ const rules = policy.net.map((n) => ({
33
+ host: n.host,
34
+ port: n.port,
35
+ blockPrivate: n.blockPrivate,
36
+ }));
37
+ // blockPrivate is OR-ed across the policy: if ANY declared rule asks for the
38
+ // private-range block, the whole config enforces it (deny wins, so a single
39
+ // rule cannot opt the proxy out of a sibling rule's blockPrivate).
40
+ const blockPrivate = rules.some((r) => r.blockPrivate);
41
+ if (opts.target === 'squid')
42
+ return lowerToSquid(rules, blockPrivate);
43
+ if (opts.target === 'nftables')
44
+ return lowerToNftables(rules, blockPrivate);
45
+ // Fail-closed on an unknown target rather than emitting a permissive default.
46
+ throw new Error(`[EGRESS_UNKNOWN_TARGET] unsupported egress target "${opts.target}"`);
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // squid — allowlist by hostname via CONNECT, no TLS interception
50
+ // ---------------------------------------------------------------------------
51
+ //
52
+ // squid matches on the CONNECT host, so it allowlists by DOMAIN cleanly and is
53
+ // the right target for rotating-CDN hostnames (api.github.com). IP-literal hosts
54
+ // are matched with a `dst` acl instead of `dstdomain`. The deny-all terminator
55
+ // is the last line, unconditional — nothing can be allowed past it.
56
+ function lowerToSquid(rules, blockPrivate) {
57
+ const notes = [];
58
+ const unenforceable = [];
59
+ const lines = ['# capgate-egress.squid.conf (generated — do not edit)'];
60
+ // ---------- blockPrivate (deny FIRST so it wins over the allows below) ----------
61
+ if (blockPrivate) {
62
+ lines.push(`acl to_private dst ${[...PRIVATE_V4, ...PRIVATE_V6].join(' ')}`);
63
+ lines.push('http_access deny to_private');
64
+ }
65
+ // ---------- allow rules ----------
66
+ rules.forEach((rule, i) => {
67
+ const dstAcl = `cg_dst_${i}`;
68
+ if (rule.host === '*') {
69
+ // squid can't allowlist "any host" as a *restriction*: `*` means the rule
70
+ // permits any destination. We represent it honestly as `dstdomain .`
71
+ // (matches every domain) and lean on blockPrivate to be the only real
72
+ // constraint left. Surfaced as a note so a reviewer sees the degeneracy.
73
+ lines.push(`acl ${dstAcl} dstdomain .`);
74
+ notes.push(`net[${i}]: host "*" degenerates to allow-any (dstdomain .) — squid cannot turn a wildcard into a restriction; only blockPrivate then constrains it.`);
75
+ }
76
+ else if (isIpLiteral(rule.host)) {
77
+ // IP literal: squid matches it with `dst`, not `dstdomain`.
78
+ lines.push(`acl ${dstAcl} dst ${rule.host}`);
79
+ }
80
+ else {
81
+ lines.push(`acl ${dstAcl} dstdomain ${rule.host}`);
82
+ }
83
+ const aclRefs = [dstAcl];
84
+ if (rule.port === null) {
85
+ // Any port → no port acl. Noted so the widened scope is auditable.
86
+ notes.push(`net[${i}]: port null (any port) — no port acl emitted for ${rule.host}.`);
87
+ }
88
+ else {
89
+ const portAcl = `cg_port_${i}`;
90
+ lines.push(`acl ${portAcl} port ${rule.port}`);
91
+ aclRefs.push(portAcl);
92
+ }
93
+ lines.push(`http_access allow ${aclRefs.join(' ')} CONNECT`);
94
+ });
95
+ if (rules.length === 0) {
96
+ notes.push('net: no egress declared — all outbound denied (deny-all only).');
97
+ }
98
+ // ---------- fail-closed terminator (unconditional, LAST line) ----------
99
+ lines.push('http_access deny all');
100
+ return {
101
+ target: 'squid',
102
+ config: lines.join('\n'),
103
+ filename: 'capgate-egress.squid.conf',
104
+ unenforceable,
105
+ notes,
106
+ };
107
+ }
108
+ // ---------------------------------------------------------------------------
109
+ // nftables — allowlist by IP+port in-kernel, bypass-proof
110
+ // ---------------------------------------------------------------------------
111
+ //
112
+ // nftables filters packets by destination IP; it cannot resolve or track
113
+ // rotating hostnames in-kernel. So hostname rules are NOT lowered to a (broken)
114
+ // rule — they are pushed to unenforceable[] with a reason pointing at the squid
115
+ // target. blockPrivate drops are emitted FIRST (before accepts), and the chain
116
+ // defaults to `policy drop` so anything not explicitly accepted is dropped.
117
+ function lowerToNftables(rules, blockPrivate) {
118
+ const notes = [];
119
+ const unenforceable = [];
120
+ const body = [];
121
+ // ---------- blockPrivate (drops FIRST, before any accept) ----------
122
+ if (blockPrivate) {
123
+ body.push(` ip daddr { ${PRIVATE_V4.join(', ')} } drop`);
124
+ body.push(` ip6 daddr { ${PRIVATE_V6.join(', ')} } drop`);
125
+ }
126
+ // ---------- accept rules ----------
127
+ rules.forEach((rule, i) => {
128
+ if (rule.host === '*') {
129
+ // Can't allowlist "any host" by IP. The blockPrivate drops above still
130
+ // apply; the allow itself is unenforceable here.
131
+ unenforceable.push({
132
+ rule,
133
+ reason: 'nftables filters IPs, not hostnames; "*" cannot be expressed as an IP allowlist. Use the "squid" target for wildcard/hostname rules.',
134
+ });
135
+ return;
136
+ }
137
+ if (!isIpLiteral(rule.host)) {
138
+ // Hostname (e.g. api.github.com): resolves to rotating CDN IPs that
139
+ // nftables can't track. Surface it; do not emit a broken rule.
140
+ unenforceable.push({
141
+ rule,
142
+ reason: `nftables filters IPs, not hostnames; ${rule.host} resolves to rotating IPs. Use the 'squid' target for hostname rules, or pin to resolved CIDRs.`,
143
+ });
144
+ return;
145
+ }
146
+ // IP literal: pick the family by colon presence and accept it.
147
+ const fam = rule.host.includes(':') ? 'ip6' : 'ip';
148
+ const dport = rule.port === null ? '' : ` tcp dport ${rule.port}`;
149
+ if (rule.port === null) {
150
+ notes.push(`net[${i}]: port null (any port) — accept emitted without tcp dport for ${rule.host}.`);
151
+ }
152
+ body.push(` ${fam} daddr ${rule.host}${dport} accept`);
153
+ });
154
+ if (rules.length === 0) {
155
+ notes.push('net: no egress declared — all outbound denied (policy drop, no accepts).');
156
+ }
157
+ if (unenforceable.length > 0) {
158
+ notes.push(`net: ${unenforceable.length} rule(s) unenforceable by nftables (hostname/wildcard) — see unenforceable[]; compile those to the "squid" target.`);
159
+ }
160
+ // ---------- assemble table (policy drop = fail-closed default) ----------
161
+ const lines = [
162
+ '# capgate-egress.nftables (generated — do not edit)',
163
+ 'table inet capgate {',
164
+ ' chain egress {',
165
+ ' type filter hook output priority 0; policy drop;',
166
+ ...body,
167
+ ' }',
168
+ '}',
169
+ ];
170
+ return {
171
+ target: 'nftables',
172
+ config: lines.join('\n'),
173
+ filename: 'capgate-egress.nftables',
174
+ unenforceable,
175
+ notes,
176
+ };
177
+ }
178
+ /**
179
+ * True if `host` is an IPv4 or IPv6 literal (vs a DNS name). Heuristic, kept
180
+ * deliberately simple: IPv4 is four dot-separated 0-255 octets; IPv6 is "has a
181
+ * colon" (real names never contain colons). This is enough to decide squid
182
+ * `dst` vs `dstdomain` and nftables accept-vs-unenforceable; we do not need a
183
+ * full RFC parser here, and over-classifying a name as an IP would only ever
184
+ * tighten matching, never loosen it.
185
+ */
186
+ function isIpLiteral(host) {
187
+ if (host.includes(':'))
188
+ return true; // IPv6 literal (names never contain ':')
189
+ const octets = host.split('.');
190
+ if (octets.length !== 4)
191
+ return false;
192
+ return octets.every((o) => /^\d{1,3}$/.test(o) && Number(o) <= 255);
193
+ }
194
+ //# sourceMappingURL=egress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.js","sourceRoot":"","sources":["../../../src/policy/adapters/egress.ts"],"names":[],"mappings":"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"}
@@ -8,4 +8,6 @@ export { lowerToBwrap } from './adapters/bwrap.js';
8
8
  export type { BwrapArtifact, BwrapOptions, EgressRule } from './adapters/bwrap.js';
9
9
  export { lowerToDocker } from './adapters/docker.js';
10
10
  export type { DockerArtifact, DockerOptions } from './adapters/docker.js';
11
+ export { lowerToEgress } from './adapters/egress.js';
12
+ export type { EgressArtifact, EgressOptions, EgressTarget } from './adapters/egress.js';
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC"}
@@ -5,4 +5,5 @@ export { parseCapability, GRAMMAR_VERSION } from './grammar.js';
5
5
  export { compile, parseManifest, normalize } from './compiler.js';
6
6
  export { lowerToBwrap } from './adapters/bwrap.js';
7
7
  export { lowerToDocker } from './adapters/docker.js';
8
+ export { lowerToEgress } from './adapters/egress.js';
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+BAA+B;AAsB/B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGhE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+BAA+B;AAsB/B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGhE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capgate",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Compile MCP tool manifests into sandbox policies (bwrap, egress rules, and more).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,6 +17,7 @@
17
17
  },
18
18
  "files": [
19
19
  "dist/",
20
+ "!dist/.tsbuildinfo",
20
21
  "LICENSE",
21
22
  "NOTICE",
22
23
  "README.md"
@@ -62,4 +63,4 @@
62
63
  "typescript": "^5.3.3",
63
64
  "vitest": "^3.2.4"
64
65
  }
65
- }
66
+ }
package/dist/.tsbuildinfo DELETED
@@ -1 +0,0 @@
1
- {"fileNames":["../node_modules/typescript/lib/lib.es5.d.ts","../node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/typescript/lib/lib.es2021.d.ts","../node_modules/typescript/lib/lib.es2022.d.ts","../node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/typescript/lib/lib.es2016.intl.d.ts","../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/typescript/lib/lib.es2021.promise.d.ts","../node_modules/typescript/lib/lib.es2021.string.d.ts","../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../node_modules/typescript/lib/lib.es2021.intl.d.ts","../node_modules/typescript/lib/lib.es2022.array.d.ts","../node_modules/typescript/lib/lib.es2022.error.d.ts","../node_modules/typescript/lib/lib.es2022.intl.d.ts","../node_modules/typescript/lib/lib.es2022.object.d.ts","../node_modules/typescript/lib/lib.es2022.string.d.ts","../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../src/policy/ir.ts","../src/policy/grammar.ts","../src/policy/compiler.ts","../src/policy/adapters/bwrap.ts","../src/policy/adapters/docker.ts","../src/policy/index.ts","../src/cli.ts","../src/index.ts","../node_modules/@types/deep-eql/index.d.ts","../node_modules/assertion-error/index.d.ts","../node_modules/@types/chai/index.d.ts","../node_modules/@types/estree/index.d.ts","../node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/@types/node/compatibility/index.d.ts","../node_modules/@types/node/globals.typedarray.d.ts","../node_modules/@types/node/buffer.buffer.d.ts","../node_modules/@types/node/globals.d.ts","../node_modules/@types/node/web-globals/abortcontroller.d.ts","../node_modules/@types/node/web-globals/domexception.d.ts","../node_modules/@types/node/web-globals/events.d.ts","../node_modules/undici-types/header.d.ts","../node_modules/undici-types/readable.d.ts","../node_modules/undici-types/file.d.ts","../node_modules/undici-types/fetch.d.ts","../node_modules/undici-types/formdata.d.ts","../node_modules/undici-types/connector.d.ts","../node_modules/undici-types/client.d.ts","../node_modules/undici-types/errors.d.ts","../node_modules/undici-types/dispatcher.d.ts","../node_modules/undici-types/global-dispatcher.d.ts","../node_modules/undici-types/global-origin.d.ts","../node_modules/undici-types/pool-stats.d.ts","../node_modules/undici-types/pool.d.ts","../node_modules/undici-types/handlers.d.ts","../node_modules/undici-types/balanced-pool.d.ts","../node_modules/undici-types/agent.d.ts","../node_modules/undici-types/mock-interceptor.d.ts","../node_modules/undici-types/mock-agent.d.ts","../node_modules/undici-types/mock-client.d.ts","../node_modules/undici-types/mock-pool.d.ts","../node_modules/undici-types/mock-errors.d.ts","../node_modules/undici-types/proxy-agent.d.ts","../node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/undici-types/retry-handler.d.ts","../node_modules/undici-types/retry-agent.d.ts","../node_modules/undici-types/api.d.ts","../node_modules/undici-types/interceptors.d.ts","../node_modules/undici-types/util.d.ts","../node_modules/undici-types/cookies.d.ts","../node_modules/undici-types/patch.d.ts","../node_modules/undici-types/websocket.d.ts","../node_modules/undici-types/eventsource.d.ts","../node_modules/undici-types/filereader.d.ts","../node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/undici-types/content-type.d.ts","../node_modules/undici-types/cache.d.ts","../node_modules/undici-types/index.d.ts","../node_modules/@types/node/web-globals/fetch.d.ts","../node_modules/@types/node/assert.d.ts","../node_modules/@types/node/assert/strict.d.ts","../node_modules/@types/node/async_hooks.d.ts","../node_modules/@types/node/buffer.d.ts","../node_modules/@types/node/child_process.d.ts","../node_modules/@types/node/cluster.d.ts","../node_modules/@types/node/console.d.ts","../node_modules/@types/node/constants.d.ts","../node_modules/@types/node/crypto.d.ts","../node_modules/@types/node/dgram.d.ts","../node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/@types/node/dns.d.ts","../node_modules/@types/node/dns/promises.d.ts","../node_modules/@types/node/domain.d.ts","../node_modules/@types/node/events.d.ts","../node_modules/@types/node/fs.d.ts","../node_modules/@types/node/fs/promises.d.ts","../node_modules/@types/node/http.d.ts","../node_modules/@types/node/http2.d.ts","../node_modules/@types/node/https.d.ts","../node_modules/@types/node/inspector.generated.d.ts","../node_modules/@types/node/module.d.ts","../node_modules/@types/node/net.d.ts","../node_modules/@types/node/os.d.ts","../node_modules/@types/node/path.d.ts","../node_modules/@types/node/perf_hooks.d.ts","../node_modules/@types/node/process.d.ts","../node_modules/@types/node/punycode.d.ts","../node_modules/@types/node/querystring.d.ts","../node_modules/@types/node/readline.d.ts","../node_modules/@types/node/readline/promises.d.ts","../node_modules/@types/node/repl.d.ts","../node_modules/@types/node/sea.d.ts","../node_modules/@types/node/stream.d.ts","../node_modules/@types/node/stream/promises.d.ts","../node_modules/@types/node/stream/consumers.d.ts","../node_modules/@types/node/stream/web.d.ts","../node_modules/@types/node/string_decoder.d.ts","../node_modules/@types/node/test.d.ts","../node_modules/@types/node/timers.d.ts","../node_modules/@types/node/timers/promises.d.ts","../node_modules/@types/node/tls.d.ts","../node_modules/@types/node/trace_events.d.ts","../node_modules/@types/node/tty.d.ts","../node_modules/@types/node/url.d.ts","../node_modules/@types/node/util.d.ts","../node_modules/@types/node/v8.d.ts","../node_modules/@types/node/vm.d.ts","../node_modules/@types/node/wasi.d.ts","../node_modules/@types/node/worker_threads.d.ts","../node_modules/@types/node/zlib.d.ts","../node_modules/@types/node/index.d.ts"],"fileIdsList":[[66,67,75,121],[75,121],[75,118,121],[75,120,121],[121],[75,121,126,154],[75,121,122,127,132,140,151,162],[75,121,122,123,132,140],[70,71,72,75,121],[75,121,124,163],[75,121,125,126,133,141],[75,121,126,151,159],[75,121,127,129,132,140],[75,120,121,128],[75,121,129,130],[75,121,131,132],[75,120,121,132],[75,121,132,133,134,151,162],[75,121,132,133,134,147,151,154],[75,121,129,132,135,140,151,162],[75,121,132,133,135,136,140,151,159,162],[75,121,135,137,151,159,162],[73,74,75,76,77,78,79,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],[75,121,132,138],[75,121,139,162,167],[75,121,129,132,140,151],[75,121,141],[75,121,142],[75,120,121,143],[75,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],[75,121,145],[75,121,146],[75,121,132,147,148],[75,121,147,149,163,165],[75,121,132,151,152,154],[75,121,153,154],[75,121,151,152],[75,121,154],[75,121,155],[75,118,121,151,156],[75,121,132,157,158],[75,121,157,158],[75,121,126,140,151,159],[75,121,160],[75,121,140,161],[75,121,135,146,162],[75,121,126,163],[75,121,151,164],[75,121,139,165],[75,121,166],[75,116,121],[75,116,121,132,134,143,151,154,162,165,167],[75,121,151,168],[75,88,92,121,162],[75,88,121,151,162],[75,83,121],[75,85,88,121,159,162],[75,121,140,159],[75,121,169],[75,83,121,169],[75,85,88,121,140,162],[75,80,81,84,87,121,132,151,162],[75,88,95,121],[75,80,86,121],[75,88,109,110,121],[75,84,88,121,154,162,169],[75,109,121,169],[75,82,83,121,169],[75,88,121],[75,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,121],[75,88,103,121],[75,88,95,96,121],[75,86,88,96,97,121],[75,87,121],[75,80,83,88,121],[75,88,92,96,97,121],[75,92,121],[75,86,88,91,121,162],[75,80,85,88,95,121],[75,121,151],[75,83,88,109,121,167,169],[63,75,121,133],[63,75,121],[58,75,121],[58,61,75,121],[58,59,75,121],[58,59,60,61,62,75,121]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"7d8d8d1c13e8cf045b846f2260e8525934696e06b729e09ef1ccd4fa004a420c","signature":"f1f76fba70cfd9ea94050567e1679fc58f8a4042bd38f2305a31c276ee2f9bf8","impliedFormat":99},{"version":"6c5aeed665c5fed8bf25e12597faa7e959873ec5bd93cef96944db527dae2fc6","signature":"4a9e2ca3b0d8615dd9720c56105980effe87bc46bf6fb3a7fb022fdce4ced178","impliedFormat":99},{"version":"03bec921d3681af3c419b13c7a88e4238c67b585ed1e5a9b0b242fec9ebc53f4","signature":"27371969b29b1d75874dfefa176fb4975f6589772b5909ea80b8c7916f9a85c4","impliedFormat":99},{"version":"3d962b2b695509d0f1601a91f5032a1e0668c603e1155df860dc9acc7011dd74","signature":"e7dba5cc3d7ab272e89e9e8d7376368149268461ba78e807cf510cb3e0e6614c","impliedFormat":99},{"version":"744ca4ec5515e70a22db3fea372bdfc7b259d720f9fe03d83c089999200c5cf8","signature":"e6589dfbc82730a9f3c2759448b081b614f980458351f06d3d17d9b5698696f5","impliedFormat":99},{"version":"2aa9a9514c800a217560213f0d77c8f0b2aa41865477db3c68cb59f8078d1170","signature":"6c59c71a60aae051f1b3117ae395d6ebcd58fb334e76233f4847e41deac5442d","impliedFormat":99},{"version":"409795758db31a8d089c950706ee10d32f81e4690a02a3646d6f6086ac46aa08","signature":"43e818adf60173644896298637f47b01d5819b17eda46eaa32d0c7d64724d012","impliedFormat":99},{"version":"4a6bdfff32fba6a5632b3e056fdc4568625ec0b91648e40d5636e42d66e47336","signature":"044d36ac72ef84f2d3639cbc25140d355f1016706c23fe48eb7744f27479c52d","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"641942a78f9063caa5d6b777c99304b7d1dc7328076038c6d94d8a0b81fc95c1","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e20d899c28ca26a2a7afc98beaa69e63ff7fba0a8bc47b4e3bf3ede5e09e424","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"372413016d17d804e1d139418aca0c68e47a83fb6669490857f4b318de8cccb3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"085f552d005479e2e6a7311cdbbe5d8c55c497b4d19274285df161ee9684cd9c","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"007faacc9268357caa21d24169f3f3f2497af3e9241308df2d89f6e6d9bb3f2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"809821b8a065e3234a55b3a9d7846231ed18d66dd749f2494c66288d890daf7f","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7c5e2ea4a9749097c347454805e933844ed207b6eefec6b7cfd418b5f5f7b28","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1}],"root":[[58,65]],"options":{"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":100,"noFallthroughCasesInSwitch":true,"noImplicitReturns":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[68,1],[66,2],[69,2],[118,3],[119,3],[120,4],[75,5],[121,6],[122,7],[123,8],[70,2],[73,9],[71,2],[72,2],[124,10],[125,11],[126,12],[127,13],[128,14],[129,15],[130,15],[131,16],[132,17],[133,18],[134,19],[76,2],[74,2],[135,20],[136,21],[137,22],[169,23],[138,24],[139,25],[140,26],[141,27],[142,28],[143,29],[144,30],[145,31],[146,32],[147,33],[148,33],[149,34],[150,2],[151,35],[153,36],[152,37],[154,38],[155,39],[156,40],[157,41],[158,42],[159,43],[160,44],[161,45],[162,46],[163,47],[164,48],[165,49],[166,50],[77,2],[78,2],[79,2],[117,51],[167,52],[168,53],[67,2],[56,2],[57,2],[11,2],[10,2],[2,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[3,2],[20,2],[21,2],[4,2],[22,2],[26,2],[23,2],[24,2],[25,2],[27,2],[28,2],[29,2],[5,2],[30,2],[31,2],[32,2],[33,2],[6,2],[37,2],[34,2],[35,2],[36,2],[38,2],[7,2],[39,2],[44,2],[45,2],[40,2],[41,2],[42,2],[43,2],[8,2],[49,2],[46,2],[47,2],[48,2],[50,2],[9,2],[51,2],[52,2],[53,2],[55,2],[54,2],[1,2],[95,54],[105,55],[94,54],[115,56],[86,57],[85,58],[114,59],[108,60],[113,61],[88,62],[102,63],[87,64],[111,65],[83,66],[82,59],[112,67],[84,68],[89,69],[90,2],[93,69],[80,2],[116,70],[106,71],[97,72],[98,73],[100,74],[96,75],[99,76],[109,59],[91,77],[92,78],[101,79],[81,80],[104,71],[103,69],[107,2],[110,81],[64,82],[65,83],[61,84],[62,85],[60,86],[59,84],[63,87],[58,2]],"version":"5.9.3"}