@orygn/opa-mcp 0.3.0 → 0.4.0
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/CHANGELOG.md +60 -3
- package/README.md +66 -31
- package/dist/config.d.ts +14 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/lib/child-env.d.ts +34 -0
- package/dist/lib/child-env.d.ts.map +1 -0
- package/dist/lib/child-env.js +144 -0
- package/dist/lib/child-env.js.map +1 -0
- package/dist/lib/conftest-cli.d.ts.map +1 -1
- package/dist/lib/conftest-cli.js +1 -0
- package/dist/lib/conftest-cli.js.map +1 -1
- package/dist/lib/opa-cli.d.ts.map +1 -1
- package/dist/lib/opa-cli.js +1 -0
- package/dist/lib/opa-cli.js.map +1 -1
- package/dist/lib/regal-cli.d.ts.map +1 -1
- package/dist/lib/regal-cli.js +1 -0
- package/dist/lib/regal-cli.js.map +1 -1
- package/dist/lib/subprocess.d.ts +36 -3
- package/dist/lib/subprocess.d.ts.map +1 -1
- package/dist/lib/subprocess.js +121 -20
- package/dist/lib/subprocess.js.map +1 -1
- package/dist/lib/tool-helpers.d.ts.map +1 -1
- package/dist/lib/tool-helpers.js +10 -0
- package/dist/lib/tool-helpers.js.map +1 -1
- package/dist/tools/authoring/check-schema.js +1 -1
- package/dist/tools/authoring/check-schema.js.map +1 -1
- package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
- package/dist/tools/evaluation/test-multiroot.js +9 -12
- package/dist/tools/evaluation/test-multiroot.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,51 @@ not part of the public surface and may change in minor releases.
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [0.4.0] - 2026-09-03
|
|
21
|
+
|
|
22
|
+
### Security
|
|
23
|
+
|
|
24
|
+
- Policies evaluated through this server no longer receive the server's environment.
|
|
25
|
+
Rego exposes the environment of the `opa` process through `opa.runtime().env`, and
|
|
26
|
+
child processes inherited `process.env`, so any evaluated policy could read
|
|
27
|
+
`OPA_TOKEN`, the `GITHUB_TOKEN` the README asks users to set for
|
|
28
|
+
`rego_playground_share`, and everything else the operator's client passed in.
|
|
29
|
+
`rego_eval` accepts inline source, so `OPA_MCP_ALLOWED_PATHS` never applied and no
|
|
30
|
+
filesystem access was needed; a policy arriving through a README, an issue, or a
|
|
31
|
+
diff was enough. `conftest_test` was affected the same way, and is the likelier
|
|
32
|
+
route to third-party policy. Children now get an explicit allow-list containing no
|
|
33
|
+
secret. `OPA_MCP_PASSTHROUGH_ENV` opts individual variables back in, and anything
|
|
34
|
+
named there is readable by evaluated policy by design.
|
|
35
|
+
|
|
36
|
+
On Windows, libuv copies a fixed set of variables to every child regardless of what
|
|
37
|
+
is requested. `USERNAME`, `USERDOMAIN` and `LOGONSERVER` cannot be removed, so they
|
|
38
|
+
are blanked rather than left to disclose the operating-system user and domain.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- A subprocess that produces very large output no longer takes the server down.
|
|
43
|
+
stdout and stderr were captured without a size limit, and decoding a capture past
|
|
44
|
+
V8's maximum string length throws inside an async `close` handler, where no tool's
|
|
45
|
+
`try`/`catch` can reach it and the process exits. A policy iterating
|
|
46
|
+
`numbers.range(1, 1000)` under `--explain full` produced 518 MiB in under seven
|
|
47
|
+
seconds, so the 30-second timeout never applied; `opa` buffers its result and writes
|
|
48
|
+
it in one burst at exit, which means the runs that complete comfortably are the
|
|
49
|
+
dangerous ones. Capture is now capped per stream, the child is stopped on overflow,
|
|
50
|
+
and the tool returns the new `OUTPUT_TOO_LARGE` error code. Configurable with
|
|
51
|
+
`OPA_MCP_MAX_SUBPROCESS_BYTES`, default 32 MiB.
|
|
52
|
+
|
|
53
|
+
- `rego_test_multiroot` reports `OUTPUT_TOO_LARGE` and `TIMEOUT` through the same mapper as
|
|
54
|
+
every other tool. It carried its own copy of the failure ladder, and a run killed for
|
|
55
|
+
producing too much output reported `OPA_BINARY_NOT_FOUND`, sending the caller after an
|
|
56
|
+
install problem that did not exist. This is the same defect that was fixed for timeouts in
|
|
57
|
+
0.3.0, in the one place that did not share the fix.
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- `OPA_MCP_MAX_SUBPROCESS_BYTES` and `OPA_MCP_PASSTHROUGH_ENV` environment variables.
|
|
62
|
+
- `OUTPUT_TOO_LARGE` error code.
|
|
63
|
+
|
|
64
|
+
|
|
20
65
|
## [0.3.0] - 2026-08-05
|
|
21
66
|
|
|
22
67
|
### Changed
|
|
@@ -983,7 +1028,19 @@ wrappers end-to-end. CI matrix: Ubuntu, macOS, and Windows on Node
|
|
|
983
1028
|
20 and 22, plus CodeQL security scanning and weekly Dependabot updates
|
|
984
1029
|
for npm, GitHub Actions, and Docker base images.
|
|
985
1030
|
|
|
986
|
-
[Unreleased]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.
|
|
1031
|
+
[Unreleased]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.4.0...HEAD
|
|
1032
|
+
[0.4.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.3.0...v0.4.0
|
|
1033
|
+
[0.3.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.2.1...v0.3.0
|
|
1034
|
+
[0.2.1]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.2.0...v0.2.1
|
|
1035
|
+
[0.2.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.20...v0.2.0
|
|
1036
|
+
[0.1.20]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.19...v0.1.20
|
|
1037
|
+
[0.1.19]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.18...v0.1.19
|
|
1038
|
+
[0.1.18]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.17...v0.1.18
|
|
1039
|
+
[0.1.17]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.16...v0.1.17
|
|
1040
|
+
[0.1.16]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.15...v0.1.16
|
|
1041
|
+
[0.1.15]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.14...v0.1.15
|
|
1042
|
+
[0.1.14]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.13...v0.1.14
|
|
1043
|
+
[0.1.13]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.12...v0.1.13
|
|
987
1044
|
[0.1.12]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.11...v0.1.12
|
|
988
1045
|
[0.1.11]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.10...v0.1.11
|
|
989
1046
|
[0.1.10]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.9...v0.1.10
|
|
@@ -994,6 +1051,6 @@ for npm, GitHub Actions, and Docker base images.
|
|
|
994
1051
|
[0.1.5]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.4...v0.1.5
|
|
995
1052
|
[0.1.4]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.3...v0.1.4
|
|
996
1053
|
[0.1.3]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.2...v0.1.3
|
|
997
|
-
[0.1.2]: https://github.com/OrygnsCode/opa-mcp-server/
|
|
998
|
-
[0.1.1]: https://github.com/OrygnsCode/opa-mcp-server/
|
|
1054
|
+
[0.1.2]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.1...v0.1.2
|
|
1055
|
+
[0.1.1]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.0...v0.1.1
|
|
999
1056
|
[0.1.0]: https://github.com/OrygnsCode/opa-mcp-server/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -22,10 +22,20 @@ environment.
|
|
|
22
22
|
+--------------------+ 52 tools +-----------------+ +---------------------+
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
> **Status:** v0.
|
|
25
|
+
> **Status:** v0.4.0. Tool surface, error codes, and
|
|
26
26
|
> environment variables follow [SemVer](https://semver.org/) from
|
|
27
27
|
> v0.1.0 forward.
|
|
28
28
|
|
|
29
|
+
> **Upgrading to 0.4.0:** subprocesses no longer inherit the server's
|
|
30
|
+
> environment. A policy that read a variable through `opa.runtime().env`
|
|
31
|
+
> will no longer see it; name the variable in `OPA_MCP_PASSTHROUGH_ENV` if
|
|
32
|
+
> it is genuinely needed. See the security section for why.
|
|
33
|
+
|
|
34
|
+
> **Upgrading to 0.3.0:** the bundled OPA is now 1.19, so Rego v0 policies
|
|
35
|
+
> no longer parse (`if` is required before a rule body, `contains` before a
|
|
36
|
+
> partial set). Run `rego_migrate_v1` to convert them. If you supply your own
|
|
37
|
+
> binary via `OPA_BINARY` or `PATH`, nothing changes.
|
|
38
|
+
|
|
29
39
|
---
|
|
30
40
|
|
|
31
41
|
## Table of contents
|
|
@@ -225,8 +235,9 @@ which opa && which regal # macOS / Linux
|
|
|
225
235
|
Get-Command opa, regal | Select-Object Source # Windows
|
|
226
236
|
```
|
|
227
237
|
|
|
228
|
-
This does not affect the **Docker**
|
|
229
|
-
|
|
238
|
+
This does not affect the **Docker** install path, which ships `opa` and
|
|
239
|
+
`regal` in the image and bypasses `PATH` entirely. The **MCPB** bundle
|
|
240
|
+
carries neither and resolves `opa` the same way the npm install does.
|
|
230
241
|
See [Troubleshooting](#troubleshooting) for full detail.
|
|
231
242
|
|
|
232
243
|
## Configuration
|
|
@@ -235,20 +246,22 @@ The server reads its configuration from environment variables. Every
|
|
|
235
246
|
variable is optional; defaults are sensible for a local OPA on
|
|
236
247
|
`http://localhost:8181`.
|
|
237
248
|
|
|
238
|
-
| Variable
|
|
239
|
-
|
|
|
240
|
-
| `OPA_URL`
|
|
241
|
-
| `OPA_TOKEN`
|
|
242
|
-
| `OPA_BINARY`
|
|
243
|
-
| `REGAL_BINARY`
|
|
244
|
-
| `CONFTEST_BINARY`
|
|
245
|
-
| `OPA_MCP_ALLOWED_PATHS`
|
|
246
|
-
| `OPA_MCP_LOG_FILE`
|
|
247
|
-
| `OPA_MCP_LOG_LEVEL`
|
|
248
|
-
| `OPA_MCP_MAX_RESPONSE_BYTES`
|
|
249
|
-
| `OPA_MCP_TIMEOUT_MS`
|
|
250
|
-
| `OPA_MCP_HTTP_TIMEOUT_MS`
|
|
251
|
-
| `OPA_MCP_NO_TELEMETRY`
|
|
249
|
+
| Variable | Default | Purpose |
|
|
250
|
+
| ------------------------------ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
251
|
+
| `OPA_URL` | `http://localhost:8181` | Base URL of an OPA REST endpoint, used by `opa_*` tools. |
|
|
252
|
+
| `OPA_TOKEN` | _(unset)_ | Bearer token for OPA, if your instance requires auth. Treated as a secret. Never echoed in logs or tool responses. |
|
|
253
|
+
| `OPA_BINARY` | `opa` (on `PATH`) | Path to the `opa` CLI, used by `rego_*` tools. |
|
|
254
|
+
| `REGAL_BINARY` | `regal` (on `PATH`) | Path to the `regal` linter. Required by `rego_lint`, `rego_fix`, and `rego_security_audit`. |
|
|
255
|
+
| `CONFTEST_BINARY` | `conftest` (on `PATH`) | Path to the `conftest` binary. Only required by `conftest_*` tools. Returns `CONFTEST_NOT_FOUND` if absent. |
|
|
256
|
+
| `OPA_MCP_ALLOWED_PATHS` | _(unset)_ | Comma- or semicolon-separated list of directories the server is allowed to read policies from. **When unset, file-based tools refuse to read from disk.** |
|
|
257
|
+
| `OPA_MCP_LOG_FILE` | `<tmpdir>/orygn-opa-mcp.log` | Path the server appends logs to. The server never writes to stdout; that channel is reserved for the MCP protocol. |
|
|
258
|
+
| `OPA_MCP_LOG_LEVEL` | `info` | One of `debug`, `info`, `warn`, `error`. |
|
|
259
|
+
| `OPA_MCP_MAX_RESPONSE_BYTES` | `100000` | Hard cap on a single tool response. Larger payloads are truncated with a `__truncated: true` marker. |
|
|
260
|
+
| `OPA_MCP_TIMEOUT_MS` | `30000` | Hard timeout for any spawned subprocess (`opa`, `regal`). After this, the child gets `SIGTERM` and then `SIGKILL`. |
|
|
261
|
+
| `OPA_MCP_HTTP_TIMEOUT_MS` | `15000` | Timeout for HTTP requests to the OPA REST API. |
|
|
262
|
+
| `OPA_MCP_NO_TELEMETRY` | _(unset)_ | Set to `1` to disable the anonymous startup ping. The ping sends the server version, OS platform, and a random install ID. The install ID is stored at `~/.orygn/opa-mcp/install-id` and is generated once on first run. No policy content or file paths are ever sent. |
|
|
263
|
+
| `OPA_MCP_MAX_SUBPROCESS_BYTES` | `33554432` (32 MiB) | Maximum bytes captured from a subprocess's stdout and stderr, counted separately. On overflow the stream is clamped, the child is stopped, and the tool returns `OUTPUT_TOO_LARGE`. Distinct from `OPA_MCP_MAX_RESPONSE_BYTES`, which trims the reply after the output is already in memory. |
|
|
264
|
+
| `OPA_MCP_PASSTHROUGH_ENV` | _(unset)_ | Comma-separated variable names to pass through to `opa`, `regal` and `conftest`. Everything else is withheld. **Anything named here is readable by any policy the server evaluates**, via `opa.runtime().env`, so use it only for values that are safe in that position. |
|
|
252
265
|
|
|
253
266
|
Paths in `OPA_MCP_ALLOWED_PATHS` and the `*_BINARY` variables must be
|
|
254
267
|
absolute. Relative paths and missing binaries are rejected with structured
|
|
@@ -269,7 +282,8 @@ Stable error codes: `INVALID_INPUT`, `INVALID_REGO`, `INVALID_BUNDLE`,
|
|
|
269
282
|
`OPA_AUTH_FAILED`, `POLICY_NOT_FOUND`, `DATA_NOT_FOUND`, `PATH_NOT_ALLOWED`,
|
|
270
283
|
`PATH_NOT_FOUND`, `DEPENDENCY_CONFLICT`, `NO_TESTS_FOUND`,
|
|
271
284
|
`COVERAGE_BELOW_THRESHOLD`, `OPA_VERSION_UNSUPPORTED`, `VERIFY_INCONCLUSIVE`,
|
|
272
|
-
`Z3_INIT_ERROR`, `GITHUB_TOKEN_MISSING`, `GIST_CREATE_FAILED`,
|
|
285
|
+
`Z3_INIT_ERROR`, `GITHUB_TOKEN_MISSING`, `GIST_CREATE_FAILED`,
|
|
286
|
+
`OUTPUT_TOO_LARGE`, `TIMEOUT`,
|
|
273
287
|
`CANCELLED`, `UNKNOWN_ERROR`.
|
|
274
288
|
|
|
275
289
|
### Category A: Authoring & static analysis
|
|
@@ -295,7 +309,7 @@ Operate on Rego source code without needing a running OPA server. Wrap
|
|
|
295
309
|
```jsonc
|
|
296
310
|
// Input
|
|
297
311
|
{
|
|
298
|
-
"source": "package x\nallow
|
|
312
|
+
"source": "package x\nallow if input.user==\"admin\""
|
|
299
313
|
}
|
|
300
314
|
|
|
301
315
|
// Output (ok)
|
|
@@ -441,7 +455,7 @@ YAML/JSON/HCL/TOML/INI against Rego policies using
|
|
|
441
455
|
// Input
|
|
442
456
|
{
|
|
443
457
|
"inlineConfig": "apiVersion: v1\nkind: Pod\nspec:\n containers:\n - name: app\n image: nginx:latest",
|
|
444
|
-
"inlinePolicy": "package main\ndeny
|
|
458
|
+
"inlinePolicy": "package main\ndeny contains msg if { input.spec.containers[_].image == \"nginx:latest\"; msg := \"pin your image tag\" }"
|
|
445
459
|
}
|
|
446
460
|
|
|
447
461
|
// Output
|
|
@@ -567,18 +581,28 @@ Agent: Done. Policy `rbac` is live on staging at $OPA_URL.
|
|
|
567
581
|
└───────────────────────────────────────────────────────────────────────────────────────┘
|
|
568
582
|
```
|
|
569
583
|
|
|
570
|
-
|
|
584
|
+
Four things worth knowing if you're going to operate this:
|
|
571
585
|
|
|
572
586
|
1. **stdout is the protocol channel.** The server logs to a file via
|
|
573
587
|
`lib/logger.ts` and never writes to stdout. If you see stray stdout
|
|
574
588
|
bytes, the client disconnects; the MCP transport layer is strict.
|
|
575
589
|
2. **No tool throws.** Every tool catches its own exceptions and returns
|
|
576
590
|
a structured `{ ok: false, error: ... }` envelope. The agent sees a
|
|
577
|
-
stable error vocabulary, not a stack trace.
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
`
|
|
581
|
-
|
|
591
|
+
stable error vocabulary, not a stack trace. Decoding subprocess output
|
|
592
|
+
happens inside an async callback, where a throw would bypass those
|
|
593
|
+
handlers entirely, so that path is bounded by bytes rather than left to
|
|
594
|
+
a `try`/`catch` that could not see it.
|
|
595
|
+
3. **Subprocesses are bounded in time, size, and environment.**
|
|
596
|
+
`lib/subprocess.ts` runs the binaries with `shell: false`, a hard
|
|
597
|
+
timeout with `SIGTERM`-then-`SIGKILL` escalation, and a per-stream byte
|
|
598
|
+
cap. There is no path through the server where an agent can construct a
|
|
599
|
+
shell command. The timeout alone is not enough: `opa` buffers a result
|
|
600
|
+
in memory and writes it in one burst at exit, so a command that finishes
|
|
601
|
+
well inside the timeout can still deliver hundreds of megabytes.
|
|
602
|
+
4. **Children do not inherit the server's environment.** `lib/child-env.ts`
|
|
603
|
+
builds an explicit allow-list instead. Rego can read its interpreter's
|
|
604
|
+
environment through `opa.runtime().env`, so anything passed down is
|
|
605
|
+
readable by any policy the server evaluates.
|
|
582
606
|
|
|
583
607
|
## Security
|
|
584
608
|
|
|
@@ -588,8 +612,18 @@ be exposed on the network.
|
|
|
588
612
|
|
|
589
613
|
- File-based tools refuse to read anything outside `OPA_MCP_ALLOWED_PATHS`.
|
|
590
614
|
When that variable is unset, file tools return `PATH_NOT_ALLOWED`.
|
|
591
|
-
- Subprocesses run with `shell: false
|
|
592
|
-
|
|
615
|
+
- Subprocesses run with `shell: false`, a hard timeout, and a byte cap on
|
|
616
|
+
captured output.
|
|
617
|
+
- **Evaluated policy cannot read the server's environment.** Rego exposes the
|
|
618
|
+
environment of the `opa` process through `opa.runtime().env`, so a child that
|
|
619
|
+
inherited `process.env` would hand `OPA_TOKEN`, `GITHUB_TOKEN`, and every
|
|
620
|
+
other variable to any policy it evaluated. Since `rego_eval` accepts inline
|
|
621
|
+
source, no filesystem access is needed to reach that, which puts it one
|
|
622
|
+
prompt injection away from any untrusted Rego an agent reads. Children get an
|
|
623
|
+
explicit allow-list instead (`lib/child-env.ts`), containing no secret.
|
|
624
|
+
`OPA_MCP_PASSTHROUGH_ENV` opts individual variables back in.
|
|
625
|
+
- `OPA_TOKEN` is never echoed in tool responses or log entries, and is not
|
|
626
|
+
passed to any child process.
|
|
593
627
|
- Releases are published with
|
|
594
628
|
[npm provenance](https://docs.npmjs.com/generating-provenance-statements);
|
|
595
629
|
the Docker image is built reproducibly from the committed `Dockerfile`.
|
|
@@ -634,8 +668,9 @@ is not enough -- the spawned server gets a reduced `PATH`. The
|
|
|
634
668
|
[`examples/`](./examples) configs already include these env vars; just
|
|
635
669
|
edit the placeholder paths.
|
|
636
670
|
|
|
637
|
-
This issue does **not** affect the Docker
|
|
638
|
-
|
|
671
|
+
This issue does **not** affect the Docker install path, which bundles
|
|
672
|
+
`opa` and `regal` and bypasses `PATH` entirely. The MCPB bundle resolves
|
|
673
|
+
`opa` from `OPA_BINARY` or `PATH`, so it can hit this.
|
|
639
674
|
|
|
640
675
|
**The server starts, then the client says "disconnected."**
|
|
641
676
|
|
|
@@ -716,7 +751,7 @@ Breaking changes will be:
|
|
|
716
751
|
|
|
717
752
|
Pinned versions of the upstream toolchain (`opa` and `regal`) are treated
|
|
718
753
|
as part of the build, not as a dependency the operator manages. The
|
|
719
|
-
Dockerfile
|
|
754
|
+
Dockerfile and CI use the same pin; bumps go through
|
|
720
755
|
Dependabot or a manual PR.
|
|
721
756
|
|
|
722
757
|
## License
|
package/dist/config.d.ts
CHANGED
|
@@ -31,6 +31,16 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
31
31
|
* write to a file path the agent specifies.
|
|
32
32
|
*/
|
|
33
33
|
maxResponseBytes: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
/**
|
|
35
|
+
* Maximum bytes captured from a subprocess's stdout and stderr, each counted
|
|
36
|
+
* separately. On overflow the stream is clamped and the child is killed.
|
|
37
|
+
*
|
|
38
|
+
* This is a memory bound, distinct from `maxResponseBytes`, which trims the
|
|
39
|
+
* response after the output has already been read into the heap. A capture
|
|
40
|
+
* past V8's max string length cannot be decoded at all, and the throw would
|
|
41
|
+
* land in an async callback where no tool can catch it.
|
|
42
|
+
*/
|
|
43
|
+
maxSubprocessBytes: z.ZodDefault<z.ZodNumber>;
|
|
34
44
|
}, "strip", z.ZodTypeAny, {
|
|
35
45
|
opaUrl: string;
|
|
36
46
|
opaBinary: string;
|
|
@@ -40,8 +50,9 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
40
50
|
httpTimeoutMs: number;
|
|
41
51
|
allowedPaths: string[];
|
|
42
52
|
logFile: string;
|
|
43
|
-
logLevel: "
|
|
53
|
+
logLevel: "error" | "debug" | "info" | "warn";
|
|
44
54
|
maxResponseBytes: number;
|
|
55
|
+
maxSubprocessBytes: number;
|
|
45
56
|
opaToken?: string | undefined;
|
|
46
57
|
}, {
|
|
47
58
|
opaUrl?: string | undefined;
|
|
@@ -53,8 +64,9 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
53
64
|
httpTimeoutMs?: number | undefined;
|
|
54
65
|
allowedPaths?: string[] | undefined;
|
|
55
66
|
logFile?: string | undefined;
|
|
56
|
-
logLevel?: "
|
|
67
|
+
logLevel?: "error" | "debug" | "info" | "warn" | undefined;
|
|
57
68
|
maxResponseBytes?: number | undefined;
|
|
69
|
+
maxSubprocessBytes?: number | undefined;
|
|
58
70
|
}>;
|
|
59
71
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
60
72
|
export declare function loadConfig(): Config;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,QAAA,MAAM,YAAY;IAChB,wEAAwE;;IASxE,2EAA2E;;IAG3E,2DAA2D;;IAG3D,+DAA+D;;IAG/D,qEAAqE;;IAGrE,kEAAkE;;IAGlE,mDAAmD;;IAGnD;;;;;OAKG;;IAGH,uEAAuE;;IAGvE,qCAAqC;;IAGrC;;;;OAIG;;IAGH;;;;;;;;OAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUH,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AA0BlD,wBAAgB,UAAU,IAAI,MAAM,CAsCnC"}
|
package/dist/config.js
CHANGED
|
@@ -9,6 +9,7 @@ import { tmpdir } from 'node:os';
|
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { resolveOpaBinary } from './lib/resolve-binary.js';
|
|
12
|
+
import { DEFAULT_MAX_OUTPUT_BYTES } from './lib/subprocess.js';
|
|
12
13
|
const ConfigSchema = z.object({
|
|
13
14
|
/** Base URL of a running OPA server (used by `opa_*` runtime tools). */
|
|
14
15
|
opaUrl: z
|
|
@@ -47,6 +48,21 @@ const ConfigSchema = z.object({
|
|
|
47
48
|
* write to a file path the agent specifies.
|
|
48
49
|
*/
|
|
49
50
|
maxResponseBytes: z.coerce.number().int().positive().default(100_000),
|
|
51
|
+
/**
|
|
52
|
+
* Maximum bytes captured from a subprocess's stdout and stderr, each counted
|
|
53
|
+
* separately. On overflow the stream is clamped and the child is killed.
|
|
54
|
+
*
|
|
55
|
+
* This is a memory bound, distinct from `maxResponseBytes`, which trims the
|
|
56
|
+
* response after the output has already been read into the heap. A capture
|
|
57
|
+
* past V8's max string length cannot be decoded at all, and the throw would
|
|
58
|
+
* land in an async callback where no tool can catch it.
|
|
59
|
+
*/
|
|
60
|
+
maxSubprocessBytes: z.coerce
|
|
61
|
+
.number()
|
|
62
|
+
.int()
|
|
63
|
+
.positive()
|
|
64
|
+
.max(DEFAULT_MAX_OUTPUT_BYTES * 8, 'OPA_MCP_MAX_SUBPROCESS_BYTES is too large to decode safely; keep it well under 512 MiB.')
|
|
65
|
+
.default(DEFAULT_MAX_OUTPUT_BYTES),
|
|
50
66
|
});
|
|
51
67
|
function parseAllowedPaths(raw) {
|
|
52
68
|
if (!raw)
|
|
@@ -69,6 +85,7 @@ const ENV_VAR_NAMES = {
|
|
|
69
85
|
logFile: 'OPA_MCP_LOG_FILE',
|
|
70
86
|
logLevel: 'OPA_MCP_LOG_LEVEL',
|
|
71
87
|
maxResponseBytes: 'OPA_MCP_MAX_RESPONSE_BYTES',
|
|
88
|
+
maxSubprocessBytes: 'OPA_MCP_MAX_SUBPROCESS_BYTES',
|
|
72
89
|
};
|
|
73
90
|
export function loadConfig() {
|
|
74
91
|
const allowedPaths = parseAllowedPaths(process.env['OPA_MCP_ALLOWED_PATHS']);
|
|
@@ -84,6 +101,7 @@ export function loadConfig() {
|
|
|
84
101
|
logFile: process.env['OPA_MCP_LOG_FILE'],
|
|
85
102
|
logLevel: process.env['OPA_MCP_LOG_LEVEL'],
|
|
86
103
|
maxResponseBytes: process.env['OPA_MCP_MAX_RESPONSE_BYTES'],
|
|
104
|
+
maxSubprocessBytes: process.env['OPA_MCP_MAX_SUBPROCESS_BYTES'],
|
|
87
105
|
});
|
|
88
106
|
if (!parsed.success) {
|
|
89
107
|
console.error('opa-mcp: invalid configuration');
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,wEAAwE;IACxE,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,EAAE;SACL,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QAClE,OAAO,EAAE,4CAA4C;KACtD,CAAC;SACD,OAAO,CAAC,uBAAuB,CAAC;IAEnC,2EAA2E;IAC3E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE/B,2DAA2D;IAC3D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAEpC,+DAA+D;IAC/D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAExC,qEAAqE;IACrE,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IAE9C,kEAAkE;IAClE,mBAAmB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IAEvE,mDAAmD;IACnD,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IAEjE;;;;;OAKG;IACH,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAE7C,uEAAuE;IACvE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC;IAEhE,qCAAqC;IACrC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAEpE;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAErE;;;;;;;;OAQG;IACH,kBAAkB,EAAE,CAAC,CAAC,MAAM;SACzB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,GAAG,CACF,wBAAwB,GAAG,CAAC,EAC5B,yFAAyF,CAC1F;SACA,OAAO,CAAC,wBAAwB,CAAC;CACrC,CAAC,CAAC;AAIH,SAAS,iBAAiB,CAAC,GAAuB;IAChD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,KAAK,GAAG,GAAG;SACd,KAAK,CAAC,MAAM,CAAC;SACb,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9C,CAAC;AAED,MAAM,aAAa,GAA2B;IAC5C,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,WAAW;IACrB,SAAS,EAAE,YAAY;IACvB,WAAW,EAAE,cAAc;IAC3B,cAAc,EAAE,iBAAiB;IACjC,mBAAmB,EAAE,oBAAoB;IACzC,aAAa,EAAE,yBAAyB;IACxC,YAAY,EAAE,uBAAuB;IACrC,OAAO,EAAE,kBAAkB;IAC3B,QAAQ,EAAE,mBAAmB;IAC7B,gBAAgB,EAAE,4BAA4B;IAC9C,kBAAkB,EAAE,8BAA8B;CACnD,CAAC;AAEF,MAAM,UAAU,UAAU;IACxB,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAE7E,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC;QACpC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAC9B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAClC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QACpC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACxC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC9C,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACtD,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;QACrD,YAAY;QACZ,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QACxC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC1C,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;QAC3D,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC;KAChE,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,MAAM,GACV,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,aAAa;gBACjD,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;gBACtB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;IAC3B,oEAAoE;IACpE,uEAAuE;IACvE,kEAAkE;IAClE,MAAM,CAAC,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the environment handed to `opa`, `regal` and `conftest`.
|
|
3
|
+
*
|
|
4
|
+
* Rego can read its interpreter's environment: `opa.runtime().env` returns the
|
|
5
|
+
* whole thing. So every variable this server passes down is readable by any
|
|
6
|
+
* policy it evaluates, and `rego_eval` takes inline source -- no filesystem
|
|
7
|
+
* access, so `OPA_MCP_ALLOWED_PATHS` never applies. Untrusted Rego reaches an
|
|
8
|
+
* agent through a README, an issue, or a pull request diff, which makes a
|
|
9
|
+
* pass-through of `process.env` a prompt injection away from handing over
|
|
10
|
+
* `OPA_TOKEN`, the `GITHUB_TOKEN` this project's own README asks users to put in
|
|
11
|
+
* their client config, and whatever else the operator's shell happens to hold.
|
|
12
|
+
*
|
|
13
|
+
* So the child gets an explicit allow-list instead. Nothing on it is a secret.
|
|
14
|
+
* Measured against the bundled OPA 1.19.0, `version`, `eval`, `check`, `test`
|
|
15
|
+
* and `build` all succeed with a completely empty environment, so the entries
|
|
16
|
+
* below exist for correctness in real-world setups (proxies, custom CA bundles,
|
|
17
|
+
* tool config discovery), not to make the binaries run.
|
|
18
|
+
*
|
|
19
|
+
* Operators who genuinely need a variable in policy can name it in
|
|
20
|
+
* `OPA_MCP_PASSTHROUGH_ENV`, which is opt-in precisely because it undoes this.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Build the child environment: the allow-list, plus any opted-in passthrough,
|
|
24
|
+
* plus `extra` from the caller (which wins, since it is explicit intent).
|
|
25
|
+
*
|
|
26
|
+
* @param extra Variables the calling command needs. Readable by evaluated
|
|
27
|
+
* policy like everything else here, so pass secrets only when the
|
|
28
|
+
* command actually requires them.
|
|
29
|
+
* @param source Environment to read from. Injectable for testing.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildChildEnv(extra?: Record<string, string>, source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
32
|
+
/** Exposed for tests and for documenting the surface. */
|
|
33
|
+
export declare const ALLOWED_CHILD_ENV_VARS: readonly string[];
|
|
34
|
+
//# sourceMappingURL=child-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-env.d.ts","sourceRoot":"","sources":["../../src/lib/child-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AA0GH;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,GAAE,MAAM,CAAC,UAAwB,GACtC,MAAM,CAAC,UAAU,CAanB;AAED,yDAAyD;AACzD,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAAY,CAAC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the environment handed to `opa`, `regal` and `conftest`.
|
|
3
|
+
*
|
|
4
|
+
* Rego can read its interpreter's environment: `opa.runtime().env` returns the
|
|
5
|
+
* whole thing. So every variable this server passes down is readable by any
|
|
6
|
+
* policy it evaluates, and `rego_eval` takes inline source -- no filesystem
|
|
7
|
+
* access, so `OPA_MCP_ALLOWED_PATHS` never applies. Untrusted Rego reaches an
|
|
8
|
+
* agent through a README, an issue, or a pull request diff, which makes a
|
|
9
|
+
* pass-through of `process.env` a prompt injection away from handing over
|
|
10
|
+
* `OPA_TOKEN`, the `GITHUB_TOKEN` this project's own README asks users to put in
|
|
11
|
+
* their client config, and whatever else the operator's shell happens to hold.
|
|
12
|
+
*
|
|
13
|
+
* So the child gets an explicit allow-list instead. Nothing on it is a secret.
|
|
14
|
+
* Measured against the bundled OPA 1.19.0, `version`, `eval`, `check`, `test`
|
|
15
|
+
* and `build` all succeed with a completely empty environment, so the entries
|
|
16
|
+
* below exist for correctness in real-world setups (proxies, custom CA bundles,
|
|
17
|
+
* tool config discovery), not to make the binaries run.
|
|
18
|
+
*
|
|
19
|
+
* Operators who genuinely need a variable in policy can name it in
|
|
20
|
+
* `OPA_MCP_PASSTHROUGH_ENV`, which is opt-in precisely because it undoes this.
|
|
21
|
+
*/
|
|
22
|
+
/** Vars every platform benefits from. Locale keeps output formatting stable. */
|
|
23
|
+
const COMMON = ['PATH', 'LANG', 'LC_ALL', 'LC_CTYPE', 'LC_NUMERIC', 'TZ'];
|
|
24
|
+
/** POSIX home and temp. Regal and Conftest look under HOME for config. */
|
|
25
|
+
const POSIX = ['HOME', 'TMPDIR', 'SHELL', 'USER', 'LOGNAME'];
|
|
26
|
+
/**
|
|
27
|
+
* Windows equivalents. A Go binary starts without these, but process creation
|
|
28
|
+
* and temp-file handling are better behaved with them present.
|
|
29
|
+
*/
|
|
30
|
+
const WINDOWS = [
|
|
31
|
+
'PATHEXT',
|
|
32
|
+
'SystemRoot',
|
|
33
|
+
'SystemDrive',
|
|
34
|
+
'COMSPEC',
|
|
35
|
+
'windir',
|
|
36
|
+
'TEMP',
|
|
37
|
+
'TMP',
|
|
38
|
+
'USERPROFILE',
|
|
39
|
+
'HOMEDRIVE',
|
|
40
|
+
'HOMEPATH',
|
|
41
|
+
'APPDATA',
|
|
42
|
+
'LOCALAPPDATA',
|
|
43
|
+
'PROCESSOR_ARCHITECTURE',
|
|
44
|
+
'NUMBER_OF_PROCESSORS',
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Proxy and TLS trust. Without these, `http.send`, bundle downloads and remote
|
|
48
|
+
* schema fetches fail behind a corporate proxy or a custom CA.
|
|
49
|
+
*
|
|
50
|
+
* A proxy URL can embed credentials, so these are the least inert entries here.
|
|
51
|
+
* They are included because breaking every corporate user is the worse trade,
|
|
52
|
+
* and they are the operator's own infrastructure credentials rather than the
|
|
53
|
+
* cloud and repository tokens that motivated this module.
|
|
54
|
+
*/
|
|
55
|
+
const NETWORK = [
|
|
56
|
+
'HTTP_PROXY',
|
|
57
|
+
'HTTPS_PROXY',
|
|
58
|
+
'NO_PROXY',
|
|
59
|
+
'ALL_PROXY',
|
|
60
|
+
'http_proxy',
|
|
61
|
+
'https_proxy',
|
|
62
|
+
'no_proxy',
|
|
63
|
+
'all_proxy',
|
|
64
|
+
'SSL_CERT_FILE',
|
|
65
|
+
'SSL_CERT_DIR',
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* Where the tools look for their own config and credentials. These name file
|
|
69
|
+
* locations; they are not themselves secrets. Conftest reads registry auth from
|
|
70
|
+
* the Docker config file, so `conftest_pull` and `conftest_push` need these.
|
|
71
|
+
*/
|
|
72
|
+
const TOOL_CONFIG = [
|
|
73
|
+
'XDG_CONFIG_HOME',
|
|
74
|
+
'XDG_CACHE_HOME',
|
|
75
|
+
'XDG_DATA_HOME',
|
|
76
|
+
'DOCKER_CONFIG',
|
|
77
|
+
'REGISTRY_AUTH_FILE',
|
|
78
|
+
];
|
|
79
|
+
const ALLOWED = [...COMMON, ...POSIX, ...WINDOWS, ...NETWORK, ...TOOL_CONFIG];
|
|
80
|
+
/** Names an operator opted into via OPA_MCP_PASSTHROUGH_ENV. */
|
|
81
|
+
function passthroughNames(source) {
|
|
82
|
+
const raw = source['OPA_MCP_PASSTHROUGH_ENV'];
|
|
83
|
+
if (!raw)
|
|
84
|
+
return [];
|
|
85
|
+
return raw
|
|
86
|
+
.split(/[;,]/)
|
|
87
|
+
.map((s) => s.trim())
|
|
88
|
+
.filter((s) => s.length > 0);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Windows treats variable names case-insensitively, and the casing in
|
|
92
|
+
* `process.env` follows whatever the parent used, so an exact-key lookup would
|
|
93
|
+
* silently miss `Path` where the list says `PATH`.
|
|
94
|
+
*/
|
|
95
|
+
function lookup(source, name) {
|
|
96
|
+
const direct = source[name];
|
|
97
|
+
if (direct !== undefined)
|
|
98
|
+
return direct;
|
|
99
|
+
if (process.platform !== 'win32')
|
|
100
|
+
return undefined;
|
|
101
|
+
const wanted = name.toLowerCase();
|
|
102
|
+
for (const key of Object.keys(source)) {
|
|
103
|
+
if (key.toLowerCase() === wanted)
|
|
104
|
+
return source[key];
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Windows-only identity variables that libuv copies from the parent no matter
|
|
110
|
+
* what environment is requested -- spawning with `{}` still delivers them, and
|
|
111
|
+
* measurably so. They are not secrets, but they name the operating-system user,
|
|
112
|
+
* the Windows domain and the domain controller, which is more than an untrusted
|
|
113
|
+
* policy needs to know about the machine evaluating it.
|
|
114
|
+
*
|
|
115
|
+
* They cannot be removed, only overwritten, so they are blanked. None of the
|
|
116
|
+
* three binaries reads them: every representative `opa` command succeeds with a
|
|
117
|
+
* completely empty environment on both platforms.
|
|
118
|
+
*/
|
|
119
|
+
const WINDOWS_IDENTITY_TO_BLANK = ['USERNAME', 'USERDOMAIN', 'LOGONSERVER'];
|
|
120
|
+
/**
|
|
121
|
+
* Build the child environment: the allow-list, plus any opted-in passthrough,
|
|
122
|
+
* plus `extra` from the caller (which wins, since it is explicit intent).
|
|
123
|
+
*
|
|
124
|
+
* @param extra Variables the calling command needs. Readable by evaluated
|
|
125
|
+
* policy like everything else here, so pass secrets only when the
|
|
126
|
+
* command actually requires them.
|
|
127
|
+
* @param source Environment to read from. Injectable for testing.
|
|
128
|
+
*/
|
|
129
|
+
export function buildChildEnv(extra, source = process.env) {
|
|
130
|
+
const env = {};
|
|
131
|
+
if (process.platform === 'win32') {
|
|
132
|
+
for (const name of WINDOWS_IDENTITY_TO_BLANK)
|
|
133
|
+
env[name] = '';
|
|
134
|
+
}
|
|
135
|
+
for (const name of [...ALLOWED, ...passthroughNames(source)]) {
|
|
136
|
+
const value = lookup(source, name);
|
|
137
|
+
if (value !== undefined)
|
|
138
|
+
env[name] = value;
|
|
139
|
+
}
|
|
140
|
+
return extra ? { ...env, ...extra } : env;
|
|
141
|
+
}
|
|
142
|
+
/** Exposed for tests and for documenting the surface. */
|
|
143
|
+
export const ALLOWED_CHILD_ENV_VARS = ALLOWED;
|
|
144
|
+
//# sourceMappingURL=child-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-env.js","sourceRoot":"","sources":["../../src/lib/child-env.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conftest-cli.d.ts","sourceRoot":"","sources":["../../src/lib/conftest-cli.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"conftest-cli.d.ts","sourceRoot":"","sources":["../../src/lib/conftest-cli.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/conftest-cli.js
CHANGED