@orygn/opa-mcp 0.3.0 → 0.5.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.
Files changed (157) hide show
  1. package/CHANGELOG.md +396 -3
  2. package/README.md +132 -98
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +8 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +15 -3
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +74 -14
  9. package/dist/config.js.map +1 -1
  10. package/dist/constants.d.ts +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/lib/bundle-signatures.d.ts +23 -0
  13. package/dist/lib/bundle-signatures.d.ts.map +1 -0
  14. package/dist/lib/bundle-signatures.js +152 -0
  15. package/dist/lib/bundle-signatures.js.map +1 -0
  16. package/dist/lib/child-env.d.ts +41 -0
  17. package/dist/lib/child-env.d.ts.map +1 -0
  18. package/dist/lib/child-env.js +176 -0
  19. package/dist/lib/child-env.js.map +1 -0
  20. package/dist/lib/conftest-cli.d.ts +25 -10
  21. package/dist/lib/conftest-cli.d.ts.map +1 -1
  22. package/dist/lib/conftest-cli.js +153 -33
  23. package/dist/lib/conftest-cli.js.map +1 -1
  24. package/dist/lib/install-id.d.ts.map +1 -1
  25. package/dist/lib/install-id.js +18 -3
  26. package/dist/lib/install-id.js.map +1 -1
  27. package/dist/lib/json-stream.d.ts +26 -0
  28. package/dist/lib/json-stream.d.ts.map +1 -0
  29. package/dist/lib/json-stream.js +69 -0
  30. package/dist/lib/json-stream.js.map +1 -0
  31. package/dist/lib/opa-cli.d.ts +64 -16
  32. package/dist/lib/opa-cli.d.ts.map +1 -1
  33. package/dist/lib/opa-cli.js +99 -28
  34. package/dist/lib/opa-cli.js.map +1 -1
  35. package/dist/lib/opa-paths.d.ts +24 -0
  36. package/dist/lib/opa-paths.d.ts.map +1 -0
  37. package/dist/lib/opa-paths.js +97 -0
  38. package/dist/lib/opa-paths.js.map +1 -0
  39. package/dist/lib/regal-cli.d.ts +16 -1
  40. package/dist/lib/regal-cli.d.ts.map +1 -1
  41. package/dist/lib/regal-cli.js +41 -6
  42. package/dist/lib/regal-cli.js.map +1 -1
  43. package/dist/lib/rego-ast-walker.d.ts.map +1 -1
  44. package/dist/lib/rego-ast-walker.js +141 -17
  45. package/dist/lib/rego-ast-walker.js.map +1 -1
  46. package/dist/lib/rego-counterexample.d.ts +1 -1
  47. package/dist/lib/rego-counterexample.d.ts.map +1 -1
  48. package/dist/lib/rego-counterexample.js +23 -5
  49. package/dist/lib/rego-counterexample.js.map +1 -1
  50. package/dist/lib/rego-ir.d.ts +32 -2
  51. package/dist/lib/rego-ir.d.ts.map +1 -1
  52. package/dist/lib/rego-smt-encoder.d.ts +53 -5
  53. package/dist/lib/rego-smt-encoder.d.ts.map +1 -1
  54. package/dist/lib/rego-smt-encoder.js +192 -26
  55. package/dist/lib/rego-smt-encoder.js.map +1 -1
  56. package/dist/lib/rego-type-inferencer.d.ts +1 -1
  57. package/dist/lib/rego-type-inferencer.d.ts.map +1 -1
  58. package/dist/lib/rego-type-inferencer.js +3 -3
  59. package/dist/lib/rego-type-inferencer.js.map +1 -1
  60. package/dist/lib/rego-verify-engine.d.ts.map +1 -1
  61. package/dist/lib/rego-verify-engine.js +109 -77
  62. package/dist/lib/rego-verify-engine.js.map +1 -1
  63. package/dist/lib/rego-z3.d.ts +10 -0
  64. package/dist/lib/rego-z3.d.ts.map +1 -1
  65. package/dist/lib/rego-z3.js +38 -0
  66. package/dist/lib/rego-z3.js.map +1 -1
  67. package/dist/lib/security.d.ts +8 -0
  68. package/dist/lib/security.d.ts.map +1 -1
  69. package/dist/lib/security.js +130 -54
  70. package/dist/lib/security.js.map +1 -1
  71. package/dist/lib/subprocess.d.ts +36 -3
  72. package/dist/lib/subprocess.d.ts.map +1 -1
  73. package/dist/lib/subprocess.js +121 -20
  74. package/dist/lib/subprocess.js.map +1 -1
  75. package/dist/lib/tool-helpers.d.ts.map +1 -1
  76. package/dist/lib/tool-helpers.js +10 -0
  77. package/dist/lib/tool-helpers.js.map +1 -1
  78. package/dist/resources/patterns.d.ts +1 -1
  79. package/dist/resources/patterns.d.ts.map +1 -1
  80. package/dist/resources/patterns.js +40 -12
  81. package/dist/resources/patterns.js.map +1 -1
  82. package/dist/server.d.ts.map +1 -1
  83. package/dist/server.js +10 -2
  84. package/dist/server.js.map +1 -1
  85. package/dist/tools/authoring/check-schema.js +1 -1
  86. package/dist/tools/authoring/check-schema.js.map +1 -1
  87. package/dist/tools/bundles/build.d.ts.map +1 -1
  88. package/dist/tools/bundles/build.js +12 -4
  89. package/dist/tools/bundles/build.js.map +1 -1
  90. package/dist/tools/bundles/sign.d.ts +9 -2
  91. package/dist/tools/bundles/sign.d.ts.map +1 -1
  92. package/dist/tools/bundles/sign.js +145 -19
  93. package/dist/tools/bundles/sign.js.map +1 -1
  94. package/dist/tools/bundles/verify.d.ts +1 -1
  95. package/dist/tools/bundles/verify.d.ts.map +1 -1
  96. package/dist/tools/bundles/verify.js +58 -19
  97. package/dist/tools/bundles/verify.js.map +1 -1
  98. package/dist/tools/conftest/pull.d.ts.map +1 -1
  99. package/dist/tools/conftest/pull.js +24 -10
  100. package/dist/tools/conftest/pull.js.map +1 -1
  101. package/dist/tools/conftest/push.d.ts.map +1 -1
  102. package/dist/tools/conftest/push.js +17 -7
  103. package/dist/tools/conftest/push.js.map +1 -1
  104. package/dist/tools/conftest/test.d.ts +10 -6
  105. package/dist/tools/conftest/test.d.ts.map +1 -1
  106. package/dist/tools/conftest/test.js +47 -24
  107. package/dist/tools/conftest/test.js.map +1 -1
  108. package/dist/tools/conftest/verify.d.ts +10 -6
  109. package/dist/tools/conftest/verify.d.ts.map +1 -1
  110. package/dist/tools/conftest/verify.js +30 -18
  111. package/dist/tools/conftest/verify.js.map +1 -1
  112. package/dist/tools/evaluation/bench.d.ts +16 -0
  113. package/dist/tools/evaluation/bench.d.ts.map +1 -1
  114. package/dist/tools/evaluation/bench.js +30 -5
  115. package/dist/tools/evaluation/bench.js.map +1 -1
  116. package/dist/tools/evaluation/exec.d.ts +16 -0
  117. package/dist/tools/evaluation/exec.d.ts.map +1 -1
  118. package/dist/tools/evaluation/exec.js +35 -2
  119. package/dist/tools/evaluation/exec.js.map +1 -1
  120. package/dist/tools/evaluation/test-multiroot.d.ts +4 -0
  121. package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
  122. package/dist/tools/evaluation/test-multiroot.js +21 -14
  123. package/dist/tools/evaluation/test-multiroot.js.map +1 -1
  124. package/dist/tools/evaluation/test.d.ts +45 -0
  125. package/dist/tools/evaluation/test.d.ts.map +1 -1
  126. package/dist/tools/evaluation/test.js +146 -27
  127. package/dist/tools/evaluation/test.js.map +1 -1
  128. package/dist/tools/helpers/coverage-gaps.d.ts +11 -3
  129. package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -1
  130. package/dist/tools/helpers/coverage-gaps.js +4 -3
  131. package/dist/tools/helpers/coverage-gaps.js.map +1 -1
  132. package/dist/tools/helpers/explain-undefined.d.ts +9 -3
  133. package/dist/tools/helpers/explain-undefined.d.ts.map +1 -1
  134. package/dist/tools/helpers/explain-undefined.js +83 -51
  135. package/dist/tools/helpers/explain-undefined.js.map +1 -1
  136. package/dist/tools/helpers/verify.d.ts.map +1 -1
  137. package/dist/tools/helpers/verify.js +5 -1
  138. package/dist/tools/helpers/verify.js.map +1 -1
  139. package/dist/tools/server-management/_shared.d.ts +15 -4
  140. package/dist/tools/server-management/_shared.d.ts.map +1 -1
  141. package/dist/tools/server-management/_shared.js +73 -12
  142. package/dist/tools/server-management/_shared.js.map +1 -1
  143. package/dist/tools/server-management/data.d.ts.map +1 -1
  144. package/dist/tools/server-management/data.js +88 -23
  145. package/dist/tools/server-management/data.js.map +1 -1
  146. package/dist/tools/server-management/decisions.d.ts.map +1 -1
  147. package/dist/tools/server-management/decisions.js +16 -3
  148. package/dist/tools/server-management/decisions.js.map +1 -1
  149. package/dist/tools/server-management/policies.d.ts.map +1 -1
  150. package/dist/tools/server-management/policies.js +44 -7
  151. package/dist/tools/server-management/policies.js.map +1 -1
  152. package/dist/tools/server-management/status.d.ts.map +1 -1
  153. package/dist/tools/server-management/status.js +80 -13
  154. package/dist/tools/server-management/status.js.map +1 -1
  155. package/dist/types.d.ts +10 -1
  156. package/dist/types.d.ts.map +1 -1
  157. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -17,6 +17,387 @@ not part of the public surface and may change in minor releases.
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
+ ## [0.5.0] - 2026-09-04
21
+
22
+ ### Security
23
+
24
+ - `opa_config` described its output as sanitized with secrets excluded. OPA
25
+ drops the `credentials` block from `GET /v1/config` but returns
26
+ `services.*.headers` verbatim, and a header is the ordinary place to put an
27
+ API key or a bearer token for a bundle service, so a live credential was
28
+ handed to whatever agent called the tool. `opa_status` returns the same
29
+ document and had the same exposure. Header values are now replaced with a
30
+ marker and the header names kept, so the document still says what the server
31
+ is configured to send.
32
+ - `rego_verify` returned `proven` and `unsatisfiable` for claims that are false,
33
+ on ordinary policy shapes, and reported no unsupported constructs while doing
34
+ it, so nothing distinguished a real proof from a wrong one. A `proven` verdict
35
+ was not usable as evidence that a policy cannot be bypassed. Every released
36
+ version is affected. Five causes, each enough on its own: clauses whose head
37
+ shape the encoder does not support were dropped rather than reported, and a
38
+ rule with every clause dropped encoded to an empty body, which is vacuously
39
+ true; head values were discarded, so `allow := false if { ... }` was encoded as
40
+ though the head were true; `default` was not encoded at all, so
41
+ `default allow := true` with a non-matching body answered `never_true`; input
42
+ references were modelled as always present, so a body reading `input.x` was
43
+ treated as defined when `x` is absent; and locals were scoped by clause index
44
+ alone, so a helper and its caller sharing a variable name collapsed into one
45
+ symbol. Encoding now fails closed: a clause holding anything the encoder cannot
46
+ represent makes the verdict `inconclusive` rather than silently shrinking the
47
+ formula. That costs coverage, and about one generated policy in sixteen now
48
+ answers `inconclusive` where it previously gave a confident wrong answer.
49
+ Numbers encode as reals rather than integers, so `input.n > 0` with
50
+ `input.n < 1` is satisfiable at 0.5 instead of being falsely refuted.
51
+ Verification also ran without a mutex on the shared solver context.
52
+ - `conftest_test` joined the `inlineConfigParser` value into the temp file name
53
+ for inline config without checking it, so a value carrying `../` segments
54
+ placed the inline config, whose content the caller also chooses, at any path
55
+ the server could write. Parser names are now a closed set (conftest 0.69's
56
+ nineteen), enforced in the schema and again in the handler, and the parser is
57
+ passed to conftest explicitly rather than through the file name.
58
+ - Path validation followed links only for paths that already existed, so a
59
+ write destination that did not exist yet, such as an `opa_bundle_build` output
60
+ or a `conftest_pull` policy directory, was accepted on its spelling alone. A
61
+ junction or symbolic link inside an allowed root that pointed outside it made
62
+ such a write land outside the roots. A path is now judged by the real location
63
+ of its nearest existing ancestor with the missing segments re-attached, a
64
+ dangling link is refused, and roots and paths are compared in canonical form,
65
+ which also ends false rejections for a root spelled through a link (macOS
66
+ `/var`), a Windows short name, or a different letter case.
67
+ - `conftest_pull` and `conftest_push` skipped the allow-list entirely when
68
+ `policy` was omitted. Both tools document that the policy directory must sit
69
+ inside `OPA_MCP_ALLOWED_PATHS`, but the omitted case fell through to the
70
+ conftest default, resolved against the working directory of the server:
71
+ `conftest_pull` wrote policy files there, outside any allowed root. The
72
+ default is now resolved and checked like an explicit path, and refused with
73
+ `PATH_NOT_ALLOWED` when it falls outside.
74
+ - `opa_bundle_sign` wrote `.signatures.json` into the server's working directory,
75
+ outside `OPA_MCP_ALLOWED_PATHS`, and reported `signed: true` while the bundle it
76
+ was asked to sign stayed unsigned. `opa sign` puts the file wherever
77
+ `--output-file-path` says, that flag defaults to the process cwd, and it was
78
+ not being passed. A directory bundle is now signed in place and an archive
79
+ beside itself (or in `outputDir`), both validated like every other path the
80
+ server writes, and success is reported only after the file is observed on
81
+ disk. A `.signatures.json` already present as a symbolic link is refused
82
+ rather than written through. The response carries the path written, the
83
+ algorithm, and the number of files covered.
84
+
85
+ ### Fixed
86
+
87
+ Results that were wrong without saying so:
88
+
89
+ - The five OPA data tools read a key containing a dot as two path segments and
90
+ returned a different document than the one asked for, with nothing to signal
91
+ the substitution. `opa_get_data` on `hosts/example.com` fetched
92
+ `/v1/data/hosts/example/com`; the same substitution applied to
93
+ `opa_put_data`, `opa_patch_data`, `opa_delete_data` and `opa_query_decision`,
94
+ so a write or a delete could land on the wrong document. A path containing a
95
+ slash now treats slash as its only separator, and a path without one is read
96
+ as dotted. Segments are percent-encoded: a key holding `?` or `#` truncated
97
+ the request URL at that character and read the parent document, and keys
98
+ holding a space, a percent sign or non-ASCII characters were unreachable.
99
+ - `opa_patch_data` documented an empty path for patching the root of the data
100
+ hierarchy, but the schema required at least one character and the path it
101
+ built for the root is one OPA answers with a redirect. Omitting both `path`
102
+ and `segments` now patches the root.
103
+ - `opa_exec` did not evaluate the rule it was asked for. Its `decision`
104
+ description told callers to pass a fully-qualified Rego reference such as
105
+ `data.authz.allow`, but `opa exec --decision` names a decision by
106
+ slash-separated path with no `data.` prefix. Any other spelling is accepted by
107
+ the flag and resolves to nothing, so every input file came back with
108
+ `opa_undefined_error`, which under a `deny`-style policy reads as a clean
109
+ pass. Both spellings are now converted to the path OPA expects, and a
110
+ reference with nothing left to name is rejected as `INVALID_INPUT`.
111
+ - `rego_test` and `rego_test_multiroot` counted a test OPA could not evaluate as
112
+ a passing test. OPA marks such a record with an `error` object and does not set
113
+ `fail`, so deriving the pass count as `total - failed - skipped` absorbed it,
114
+ and a suite whose tests all raised (a rule conflict, for instance) was reported
115
+ as fully passing with zero failures. Both tools now report `errored`
116
+ separately, and the multiroot aggregate carries `totalErrored`.
117
+ - Windows: a data document passed by absolute path was loaded under its drive
118
+ letter instead of where the policy expected it. OPA reads every load path as
119
+ an optional `prefix:path` pair and splits on the first colon, so
120
+ `C:\policies\data.json` mounted at `data.C` and a rule reading `data.tier`
121
+ found nothing, while the tool reported success. `opa test` on a suite whose
122
+ tests read data reported those tests as failing. Load paths are now passed
123
+ relative to a directory the `opa` process runs in, which is the only spelling
124
+ OPA reads correctly. Rego modules are unaffected either way, because a module
125
+ mounts at its own `package` rather than at its path, which is why policies
126
+ worked and only their data did not. Nothing changes on macOS or Linux, whose
127
+ absolute paths carry no drive letter. Load paths spanning two drives are now
128
+ reported as an error, since OPA cannot load documents from two drives in one
129
+ invocation.
130
+ - The ABAC example in the `opa://patterns` resource failed to evaluate on the
131
+ case it exists to handle. It expressed "hide secret resources from other
132
+ organizations" as a second rule assigning `allow := false`, which in Rego is a
133
+ conflict rather than an override: a user reading their own secret resource
134
+ from another organization got `eval_conflict_error` instead of a denial. The
135
+ denial is now a condition the permissive rules consult. The pitfalls list,
136
+ which recommended the broken form, says why it does not work.
137
+ - The Terraform example in the `opa://patterns` resource did not reject a
138
+ full-admin IAM policy. It tested `"*" in statement.Action`, which requires
139
+ `Action` to be a collection, and AWS accepts a bare string there, in
140
+ `Resource`, and for `Statement` itself. Of the four ways to spell
141
+ `Allow * on *`, the rule caught one; the most common form,
142
+ `{"Action": "*", "Resource": "*"}`, was allowed. Each position is now widened
143
+ to a set before the wildcard test. Scoped policies and `Deny` statements are
144
+ still allowed, so the rule has not become indiscriminate.
145
+ - `rego_test` with `coverage` or `threshold` reported `One or more tests
146
+ failed` for a suite where none did. A suite holding a `todo_` test exits
147
+ non-zero under `--coverage` with an empty stderr, and the coverage report is
148
+ on stdout as asked for. The report was discarded and the run called a
149
+ failure. A non-zero exit with a parseable report and no failure lines is now
150
+ the coverage result it is, and a report OPA did produce is kept in the error
151
+ details when tests really did fail.
152
+ - `rego_coverage_gaps` reported `testsPassed`, `testsFailed` and
153
+ `testsSkipped` as zero on every call. OPA emits no per-test records in
154
+ coverage mode, so the three counts could never be anything else, and three
155
+ zeros read as "no tests ran" rather than "not reported". They are now
156
+ omitted unless OPA supplied records.
157
+ - `opa_health` reported a reachable server as `OPA_UNREACHABLE`. A server that
158
+ answers `/health?bundles=true` with `one or more bundles are not activated`
159
+ is running; the caller was told no server was found and to go start one, and
160
+ OPA's own reason was buried in a stringified error. Such a response is now a
161
+ result, `healthy: false` with `reason`. A 401 maps to `OPA_AUTH_FAILED`, and
162
+ `OPA_UNREACHABLE` is left for a server that could not be reached.
163
+
164
+ Tools that did not work as documented:
165
+
166
+ - `opa_bundle_verify` passed `--verification-key` to `opa eval`, which has no
167
+ such flag, so verification always failed with "unknown flag" and was reported
168
+ as `INVALID_BUNDLE`, signed or not. Verification now runs through
169
+ `opa build --verification-key` into a discarded temp file, which is the path
170
+ OPA provides. Failures carry `details.reason`: `signature_invalid`,
171
+ `scope_mismatch`, `file_modified`, `file_added`, `file_missing`,
172
+ `file_unparseable`, `unsigned`, `signatures_malformed`, `not_a_bundle`,
173
+ `bundle_load_error`, or `unknown` when OPA's message is not recognised. A key
174
+ or algorithm OPA cannot use is reported as `INVALID_INPUT` by both tools.
175
+ - Directory bundles are signed and verified by name from the parent directory,
176
+ the way `opa sign --bundle <name>` records them, so a signed directory stays
177
+ valid wherever it is placed under that name and a directory signed with the
178
+ OPA CLI verifies. A symbolic link or junction given as the bundle is resolved
179
+ first; OPA does not descend a linked root and would sign an empty file list.
180
+ - `opa_bundle_build` passed `--signing-key` and `--verification-key` without
181
+ `--bundle`, which `opa build` refuses, so neither option worked unless
182
+ `bundle: true` was also set. Either option now implies bundle mode.
183
+ - `opa_bundle_sign` returned an empty `stderr` on failure because `opa sign`
184
+ prints its errors on stdout. `details` now carries both streams.
185
+ - `conftest_test` and `conftest_verify` threw `UNKNOWN_ERROR` on every clean run.
186
+ conftest omits every empty array from its JSON, so a passing file arrives with
187
+ no `failures` key and the summary code dereferenced it. Results now always
188
+ carry their arrays, `conftest_verify` reports `NO_TESTS_FOUND` for a policy
189
+ directory with no test rules (conftest prints `null` there), and both
190
+ summaries count files by name, since conftest emits one entry per namespace
191
+ or per test rule. `summary.successes` and `summary.failures` are added to
192
+ `conftest_test`. `exceptions` are messages, not strings, matching conftest.
193
+ - `conftest_pull` did not write to the directory it was given. Conftest resolves
194
+ `--policy` against the working directory rather than honouring an absolute
195
+ path, and the tool resolves the caller's path against the allow-list before
196
+ handing it over, so the path was always absolute. On Windows the pull failed
197
+ outright, reporting a path of the form `.\C:\...`. `conftest_push` had the
198
+ same handling and read from the same path on whichever drive it happened to
199
+ start on. Both now run from the parent directory and name the target
200
+ relatively.
201
+ - `rego_test` with `count` above 1 reported the suite as having no tests. OPA
202
+ prints one pretty-printed JSON array per repetition, back to back, which is
203
+ neither a single JSON value nor one record per line, so nothing parsed and the
204
+ tool returned `NO_TESTS_FOUND` for a suite that had just run. The repetitions
205
+ are now read and collapsed to one record per test carrying its worst outcome,
206
+ so a test that fails intermittently is reported as failing.
207
+ - `rego_test` did not populate `parameterizedGroups`. OPA reports a
208
+ `test_x[case]` rule as a single record carrying the per-case outcomes in
209
+ `sub_results`, not as one record per case, so looking for a bracketed test
210
+ name found nothing on any OPA 1.x run. A rule whose cases mostly passed was
211
+ reported as one failing test with no indication of which case failed. The
212
+ cases are now grouped under the rule name, and the bracketed form older
213
+ versions emitted is still read.
214
+ - `rego_bench` failed with `UNKNOWN_ERROR` for any `count` above 1. OPA prints
215
+ one JSON document per repetition, back to back, which is not a single JSON
216
+ value, so nothing parsed. Every repetition is now returned in `runs`, and the
217
+ top-level figures come from the fastest of them per iteration.
218
+ - `rego_bench` reported a failed benchmark with an empty error. `opa bench
219
+ --format=json` writes its diagnostics to stdout as an `errors` array and
220
+ leaves stderr empty, and the tool reported only stderr, so a query with a
221
+ syntax error came back as `EVAL_ERROR` with nothing in it. The diagnostics
222
+ are now included.
223
+ - `opa_list_policies` returned nothing but a truncation notice on a server
224
+ holding more than a couple of dozen policies. OPA answers the policy
225
+ endpoints with each policy's parsed AST alongside its source, and the AST is
226
+ far larger than the text it came from, so the response passed
227
+ `OPA_MCP_MAX_RESPONSE_BYTES` and the payload was replaced with advice to
228
+ narrow the scope. The tool took no arguments, so there was no scope to
229
+ narrow. It now returns the policy IDs and a count, with `includeSource` and
230
+ `includeAst` to ask for more.
231
+ - `opa_get_policy` returned the AST alongside the source, which nothing had
232
+ asked for: a 477-byte policy came back as a 19 KB response. The AST is now
233
+ behind `includeAst`.
234
+ - The server did nothing when it was reached through a symbolic link. Its
235
+ entry-point check compared `import.meta.url` with `process.argv[1]` as
236
+ strings, and Node resolves symlinks for a module's own URL while leaving
237
+ `argv[1]` as it was invoked, so the two differed and neither the CLI flags nor
238
+ the transport ran: the process started and exited in silence. npm's `bin`
239
+ entry is a symlink on macOS and Linux. The comparison is now between real
240
+ paths, so how the file was reached no longer matters.
241
+ - `rego_explain_undefined` had nothing to say about a policy written with
242
+ `default allow := false`. A default gives the query a value, so it is never
243
+ undefined and the tool returned that value and stopped, skipping the
244
+ per-clause analysis it exists for. A query whose value came from a default
245
+ and from nothing else is now analysed, and `queryResult` reports `default`.
246
+ - Clauses of a multi-clause rule were not told apart in the trace. OPA leaves
247
+ `Node.location` unset on trace events, so the row comparison meant to
248
+ distinguish them always fell through to matching on the rule name, and every
249
+ clause looked present in the trace as soon as one was. Those clauses were
250
+ never evaluated standalone: each came back with every condition
251
+ `unevaluable` and no blocking condition. The event's own location is now
252
+ used.
253
+ - `rego_lint`, `rego_fix` and `rego_security_audit` ignored the linted project's
254
+ own `.regal/config.yaml`, and applied any configuration sitting above the
255
+ server's working directory to every call instead. Regal discovers its
256
+ configuration by walking up from its own working directory rather than from
257
+ the files it is given, and it was spawned without one, so it inherited the
258
+ server's, which for a stdio server is wherever the client launched it. Rules a
259
+ project had turned off were reported anyway, and inline source, which belongs
260
+ to no project, picked up whatever happened to be above the server. Regal now
261
+ runs in the directory of what it is linting, and inline source runs in its own
262
+ temp directory. An explicit `configFile` still takes precedence.
263
+
264
+ Configuration and environment:
265
+
266
+ - An empty or blank environment variable was treated as a real value.
267
+ `OPA_BINARY=""`, which is what a shell leaves behind when it expands an
268
+ unset variable, is not the literal default `opa`, so binary resolution
269
+ skipped the bundled build and every `rego_*` call tried to spawn nothing.
270
+ Blank now means unset for every variable the server reads, and values are
271
+ trimmed.
272
+ - `OPA_MCP_TIMEOUT_MS` and `OPA_MCP_HTTP_TIMEOUT_MS` accepted values Node
273
+ cannot represent. A timer of 2147483648 ms or more is clamped to 1 ms with
274
+ only a process warning, so a large value set to mean "effectively no
275
+ timeout" timed out every subprocess and every HTTP call immediately. Values
276
+ above 2147483647 are now refused at startup with a message saying why.
277
+ - An `install-id` file that existed but held no id was a permanent trap. The
278
+ read found no id, the exclusive create failed because the file was there, and
279
+ the fallback read found no id again, on every run for the life of the machine.
280
+ The file is now rewritten when it holds no usable id; a brand-new file is
281
+ still created exclusively so two first runs cannot both claim it. A file can
282
+ end up empty after a crash or a full disk during the first run.
283
+ - The test suites no longer emit telemetry pings.
284
+
285
+ ### Added
286
+
287
+ - `opa_bundle_sign` accepts `outputDir` for archives, the directory that
288
+ receives `.signatures.json`. A directory bundle is always signed in place,
289
+ since OPA only reads the signature from inside the bundle.
290
+ - `opa_bundle_verify` accepts `v0Compatible` for bundles written in Rego v0,
291
+ which otherwise fail to load after the signature has been checked.
292
+ - The five OPA data tools accept `segments`, an array of literal key segments,
293
+ for keys that contain both a dot and a slash and so cannot be written as a
294
+ path string. `opa_put_data`, `opa_patch_data` and `opa_delete_data` return the
295
+ resolved `segments` alongside the `path` that was supplied.
296
+ - `opa_exec` output gains `hint`, present when every input left the decision
297
+ undefined. That is the expected outcome when no rule matched and also what a
298
+ decision naming nothing looks like, and the per-file results do not
299
+ distinguish them.
300
+ - `OPA_MCP_BLOCK_ENV` withholds named variables from `opa`, `regal` and
301
+ `conftest` even when they are on the built-in allow-list. It is applied last,
302
+ so it also overrides `OPA_MCP_PASSTHROUGH_ENV` and anything a command passes
303
+ explicitly. It exists so an operator behind an authenticated proxy can choose
304
+ to lose proxy support rather than expose those credentials to evaluated
305
+ policy.
306
+
307
+ ### Changed
308
+
309
+ - `rego_test` output gains `errored`, `repetitions` (present only when more
310
+ than one repetition ran; OPA stops repeating at the first run that fails, so
311
+ this can be lower than the requested `count`) and `caseCounts` (present only
312
+ when the run had a parameterized test; the top-level counts still follow OPA
313
+ and treat such a rule as one test however many cases it holds).
314
+ `rego_test_multiroot` gains `errored` per root and `totalErrored` overall.
315
+ - `opa_list_policies` output gains `count`.
316
+ - `rego_explain_undefined` output: `queryResult` gains `default`, and `value`
317
+ is populated for it. On a query that is genuinely defined the tool now also
318
+ runs `opa parse`, which is how it tells a default apart from a rule that
319
+ matched.
320
+ - `OPA_MCP_ALLOWED_PATHS` now refuses a relative entry, as documented. A
321
+ relative root was resolved against the server's working directory, so for a
322
+ stdio server the same configuration permitted different directories depending
323
+ on how the client launched it.
324
+ - `opa-mcp --help` lists `OPA_MCP_MAX_SUBPROCESS_BYTES`,
325
+ `OPA_MCP_PASSTHROUGH_ENV` and `OPA_MCP_NO_TELEMETRY`, which were documented
326
+ but absent from the output an invalid-configuration message points at.
327
+ - The 0.4.0 entry below, the README and the source comment all described the
328
+ child-process allow-list as containing no secret. It carries no cloud or
329
+ repository credential, but `HTTP_PROXY`, `HTTPS_PROXY` and `ALL_PROXY` are on
330
+ it and a proxy URL can embed a username and password, which any evaluated
331
+ policy can read through `opa.runtime().env`. All three now say so. No
332
+ behaviour changed; the exposure was there in 0.4.0 as shipped and is
333
+ unchanged by this correction.
334
+ - Documentation corrected where it did not match the tools: `opa_status`
335
+ returns `GET /v1/config`, not bundle or decision-log status;
336
+ `rego_describe_policy` does not report input references, so the two prompts
337
+ that told the model to use it for that now name `rego_infer_input_schema`;
338
+ `rego_lint` returns a flat list of violations rather than findings grouped by
339
+ category; `rego_capabilities` reflects the resolved `opa` binary rather than
340
+ the bundled one; `rego_explain_decision` returns a structured summary rather
341
+ than a natural-language explanation, and the extension manifest no longer
342
+ says the helper tools use AI; the MCPB bundle has no bundled-binary fallback;
343
+ unit tests run on macOS only on Node 22.
344
+ - Four error codes that nothing returns are no longer listed as codes a caller
345
+ can expect: `REGAL_VERSION_TOO_OLD`, `DEPENDENCY_CONFLICT`,
346
+ `VERIFY_INCONCLUSIVE` and `Z3_INIT_ERROR`. They remain reserved in the type.
347
+ The troubleshooting entry for a Regal minimum-version check that does not
348
+ exist is removed.
349
+
350
+ ## [0.4.0] - 2026-09-03
351
+
352
+ ### Security
353
+
354
+ - Policies evaluated through this server no longer receive the server's environment.
355
+ Rego exposes the environment of the `opa` process through `opa.runtime().env`, and
356
+ child processes inherited `process.env`, so any evaluated policy could read
357
+ `OPA_TOKEN`, the `GITHUB_TOKEN` the README asks users to set for
358
+ `rego_playground_share`, and everything else the operator's client passed in.
359
+ `rego_eval` accepts inline source, so `OPA_MCP_ALLOWED_PATHS` never applied and no
360
+ filesystem access was needed; a policy arriving through a README, an issue, or a
361
+ diff was enough. `conftest_test` was affected the same way, and is the likelier
362
+ route to third-party policy. Children now get an explicit allow-list.
363
+ `OPA_MCP_PASSTHROUGH_ENV` opts individual variables back in, and anything named
364
+ there is readable by evaluated policy by design.
365
+
366
+ The allow-list carries no cloud or repository token, but it is not free of
367
+ credentials: `HTTP_PROXY`, `HTTPS_PROXY` and `ALL_PROXY` are on it, and a proxy
368
+ URL can embed a username and password, so an operator behind an authenticated
369
+ corporate proxy is still handing those to evaluated policy. They are on the list
370
+ because dropping them breaks proxied bundle downloads and `http.send`.
371
+
372
+ On Windows, libuv copies a fixed set of variables to every child regardless of what
373
+ is requested. `USERNAME`, `USERDOMAIN` and `LOGONSERVER` cannot be removed, so they
374
+ are blanked rather than left to disclose the operating-system user and domain.
375
+
376
+ ### Fixed
377
+
378
+ - A subprocess that produces very large output no longer takes the server down.
379
+ stdout and stderr were captured without a size limit, and decoding a capture past
380
+ V8's maximum string length throws inside an async `close` handler, where no tool's
381
+ `try`/`catch` can reach it and the process exits. A policy iterating
382
+ `numbers.range(1, 1000)` under `--explain full` produced 518 MiB in under seven
383
+ seconds, so the 30-second timeout never applied; `opa` buffers its result and writes
384
+ it in one burst at exit, which means the runs that complete comfortably are the
385
+ dangerous ones. Capture is now capped per stream, the child is stopped on overflow,
386
+ and the tool returns the new `OUTPUT_TOO_LARGE` error code. Configurable with
387
+ `OPA_MCP_MAX_SUBPROCESS_BYTES`, default 32 MiB.
388
+
389
+ - `rego_test_multiroot` reports `OUTPUT_TOO_LARGE` and `TIMEOUT` through the same mapper as
390
+ every other tool. It carried its own copy of the failure ladder, and a run killed for
391
+ producing too much output reported `OPA_BINARY_NOT_FOUND`, sending the caller after an
392
+ install problem that did not exist. This is the same defect that was fixed for timeouts in
393
+ 0.3.0, in the one place that did not share the fix.
394
+
395
+ ### Added
396
+
397
+ - `OPA_MCP_MAX_SUBPROCESS_BYTES` and `OPA_MCP_PASSTHROUGH_ENV` environment variables.
398
+ - `OUTPUT_TOO_LARGE` error code.
399
+
400
+
20
401
  ## [0.3.0] - 2026-08-05
21
402
 
22
403
  ### Changed
@@ -983,7 +1364,19 @@ wrappers end-to-end. CI matrix: Ubuntu, macOS, and Windows on Node
983
1364
  20 and 22, plus CodeQL security scanning and weekly Dependabot updates
984
1365
  for npm, GitHub Actions, and Docker base images.
985
1366
 
986
- [Unreleased]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.12...HEAD
1367
+ [Unreleased]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.4.0...HEAD
1368
+ [0.4.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.3.0...v0.4.0
1369
+ [0.3.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.2.1...v0.3.0
1370
+ [0.2.1]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.2.0...v0.2.1
1371
+ [0.2.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.20...v0.2.0
1372
+ [0.1.20]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.19...v0.1.20
1373
+ [0.1.19]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.18...v0.1.19
1374
+ [0.1.18]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.17...v0.1.18
1375
+ [0.1.17]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.16...v0.1.17
1376
+ [0.1.16]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.15...v0.1.16
1377
+ [0.1.15]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.14...v0.1.15
1378
+ [0.1.14]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.13...v0.1.14
1379
+ [0.1.13]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.12...v0.1.13
987
1380
  [0.1.12]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.11...v0.1.12
988
1381
  [0.1.11]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.10...v0.1.11
989
1382
  [0.1.10]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.9...v0.1.10
@@ -994,6 +1387,6 @@ for npm, GitHub Actions, and Docker base images.
994
1387
  [0.1.5]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.4...v0.1.5
995
1388
  [0.1.4]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.3...v0.1.4
996
1389
  [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/releases/tag/v0.1.2
998
- [0.1.1]: https://github.com/OrygnsCode/opa-mcp-server/releases/tag/v0.1.1
1390
+ [0.1.2]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.1...v0.1.2
1391
+ [0.1.1]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.1.0...v0.1.1
999
1392
  [0.1.0]: https://github.com/OrygnsCode/opa-mcp-server/releases/tag/v0.1.0