@orygn/opa-mcp 0.4.0 → 0.6.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 (236) hide show
  1. package/CHANGELOG.md +583 -4
  2. package/README.md +144 -98
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +9 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +14 -4
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +91 -19
  9. package/dist/config.js.map +1 -1
  10. package/dist/constants.d.ts +1 -6
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +17 -3
  13. package/dist/constants.js.map +1 -1
  14. package/dist/lib/bundle-signatures.d.ts +23 -0
  15. package/dist/lib/bundle-signatures.d.ts.map +1 -0
  16. package/dist/lib/bundle-signatures.js +152 -0
  17. package/dist/lib/bundle-signatures.js.map +1 -0
  18. package/dist/lib/child-env.d.ts +9 -2
  19. package/dist/lib/child-env.d.ts.map +1 -1
  20. package/dist/lib/child-env.js +38 -6
  21. package/dist/lib/child-env.js.map +1 -1
  22. package/dist/lib/conftest-cli.d.ts +25 -10
  23. package/dist/lib/conftest-cli.d.ts.map +1 -1
  24. package/dist/lib/conftest-cli.js +233 -50
  25. package/dist/lib/conftest-cli.js.map +1 -1
  26. package/dist/lib/errors.d.ts +4 -5
  27. package/dist/lib/errors.d.ts.map +1 -1
  28. package/dist/lib/errors.js +15 -3
  29. package/dist/lib/errors.js.map +1 -1
  30. package/dist/lib/inline-paths.d.ts +37 -0
  31. package/dist/lib/inline-paths.d.ts.map +1 -0
  32. package/dist/lib/inline-paths.js +162 -0
  33. package/dist/lib/inline-paths.js.map +1 -0
  34. package/dist/lib/install-id.d.ts.map +1 -1
  35. package/dist/lib/install-id.js +18 -3
  36. package/dist/lib/install-id.js.map +1 -1
  37. package/dist/lib/json-stream.d.ts +26 -0
  38. package/dist/lib/json-stream.d.ts.map +1 -0
  39. package/dist/lib/json-stream.js +69 -0
  40. package/dist/lib/json-stream.js.map +1 -0
  41. package/dist/lib/opa-cli.d.ts +74 -16
  42. package/dist/lib/opa-cli.d.ts.map +1 -1
  43. package/dist/lib/opa-cli.js +107 -30
  44. package/dist/lib/opa-cli.js.map +1 -1
  45. package/dist/lib/opa-client.d.ts +27 -1
  46. package/dist/lib/opa-client.d.ts.map +1 -1
  47. package/dist/lib/opa-client.js +98 -14
  48. package/dist/lib/opa-client.js.map +1 -1
  49. package/dist/lib/opa-paths.d.ts +34 -0
  50. package/dist/lib/opa-paths.d.ts.map +1 -0
  51. package/dist/lib/opa-paths.js +101 -0
  52. package/dist/lib/opa-paths.js.map +1 -0
  53. package/dist/lib/output.d.ts.map +1 -1
  54. package/dist/lib/output.js +83 -10
  55. package/dist/lib/output.js.map +1 -1
  56. package/dist/lib/regal-cli.d.ts +16 -1
  57. package/dist/lib/regal-cli.d.ts.map +1 -1
  58. package/dist/lib/regal-cli.js +40 -6
  59. package/dist/lib/regal-cli.js.map +1 -1
  60. package/dist/lib/rego-ast-walker.d.ts +0 -6
  61. package/dist/lib/rego-ast-walker.d.ts.map +1 -1
  62. package/dist/lib/rego-ast-walker.js +181 -55
  63. package/dist/lib/rego-ast-walker.js.map +1 -1
  64. package/dist/lib/rego-counterexample.d.ts +15 -2
  65. package/dist/lib/rego-counterexample.d.ts.map +1 -1
  66. package/dist/lib/rego-counterexample.js +63 -15
  67. package/dist/lib/rego-counterexample.js.map +1 -1
  68. package/dist/lib/rego-input-path.d.ts +20 -0
  69. package/dist/lib/rego-input-path.d.ts.map +1 -0
  70. package/dist/lib/rego-input-path.js +70 -0
  71. package/dist/lib/rego-input-path.js.map +1 -0
  72. package/dist/lib/rego-ir.d.ts +34 -3
  73. package/dist/lib/rego-ir.d.ts.map +1 -1
  74. package/dist/lib/rego-smt-encoder.d.ts +88 -5
  75. package/dist/lib/rego-smt-encoder.d.ts.map +1 -1
  76. package/dist/lib/rego-smt-encoder.js +270 -31
  77. package/dist/lib/rego-smt-encoder.js.map +1 -1
  78. package/dist/lib/rego-type-inferencer.d.ts +27 -2
  79. package/dist/lib/rego-type-inferencer.d.ts.map +1 -1
  80. package/dist/lib/rego-type-inferencer.js +71 -3
  81. package/dist/lib/rego-type-inferencer.js.map +1 -1
  82. package/dist/lib/rego-verify-engine.d.ts.map +1 -1
  83. package/dist/lib/rego-verify-engine.js +203 -90
  84. package/dist/lib/rego-verify-engine.js.map +1 -1
  85. package/dist/lib/rego-z3.d.ts +66 -0
  86. package/dist/lib/rego-z3.d.ts.map +1 -1
  87. package/dist/lib/rego-z3.js +312 -5
  88. package/dist/lib/rego-z3.js.map +1 -1
  89. package/dist/lib/security.d.ts +8 -0
  90. package/dist/lib/security.d.ts.map +1 -1
  91. package/dist/lib/security.js +130 -54
  92. package/dist/lib/security.js.map +1 -1
  93. package/dist/lib/subprocess.d.ts +13 -0
  94. package/dist/lib/subprocess.d.ts.map +1 -1
  95. package/dist/lib/subprocess.js +153 -18
  96. package/dist/lib/subprocess.js.map +1 -1
  97. package/dist/lib/tool-helpers.d.ts +12 -25
  98. package/dist/lib/tool-helpers.d.ts.map +1 -1
  99. package/dist/lib/tool-helpers.js +66 -40
  100. package/dist/lib/tool-helpers.js.map +1 -1
  101. package/dist/prompts/index.js +2 -2
  102. package/dist/resources/index.js +1 -1
  103. package/dist/resources/index.js.map +1 -1
  104. package/dist/resources/patterns.d.ts +1 -1
  105. package/dist/resources/patterns.d.ts.map +1 -1
  106. package/dist/resources/patterns.js +42 -15
  107. package/dist/resources/patterns.js.map +1 -1
  108. package/dist/server.d.ts +2 -2
  109. package/dist/server.d.ts.map +1 -1
  110. package/dist/server.js +50 -7
  111. package/dist/server.js.map +1 -1
  112. package/dist/tools/authoring/capabilities.d.ts +4 -0
  113. package/dist/tools/authoring/capabilities.d.ts.map +1 -1
  114. package/dist/tools/authoring/capabilities.js +41 -4
  115. package/dist/tools/authoring/capabilities.js.map +1 -1
  116. package/dist/tools/authoring/check-schema.d.ts +6 -0
  117. package/dist/tools/authoring/check-schema.d.ts.map +1 -1
  118. package/dist/tools/authoring/check-schema.js +56 -3
  119. package/dist/tools/authoring/check-schema.js.map +1 -1
  120. package/dist/tools/authoring/format.d.ts.map +1 -1
  121. package/dist/tools/authoring/format.js +2 -2
  122. package/dist/tools/authoring/format.js.map +1 -1
  123. package/dist/tools/authoring/lint.d.ts.map +1 -1
  124. package/dist/tools/authoring/lint.js +8 -6
  125. package/dist/tools/authoring/lint.js.map +1 -1
  126. package/dist/tools/authoring/migrate-v1.d.ts.map +1 -1
  127. package/dist/tools/authoring/migrate-v1.js +20 -4
  128. package/dist/tools/authoring/migrate-v1.js.map +1 -1
  129. package/dist/tools/authoring/parse.d.ts.map +1 -1
  130. package/dist/tools/authoring/parse.js +3 -3
  131. package/dist/tools/authoring/parse.js.map +1 -1
  132. package/dist/tools/bundles/build.d.ts.map +1 -1
  133. package/dist/tools/bundles/build.js +12 -4
  134. package/dist/tools/bundles/build.js.map +1 -1
  135. package/dist/tools/bundles/sign.d.ts +9 -2
  136. package/dist/tools/bundles/sign.d.ts.map +1 -1
  137. package/dist/tools/bundles/sign.js +125 -19
  138. package/dist/tools/bundles/sign.js.map +1 -1
  139. package/dist/tools/bundles/verify.d.ts +1 -1
  140. package/dist/tools/bundles/verify.d.ts.map +1 -1
  141. package/dist/tools/bundles/verify.js +58 -19
  142. package/dist/tools/bundles/verify.js.map +1 -1
  143. package/dist/tools/conftest/index.d.ts +5 -0
  144. package/dist/tools/conftest/index.d.ts.map +1 -1
  145. package/dist/tools/conftest/index.js.map +1 -1
  146. package/dist/tools/conftest/pull.d.ts.map +1 -1
  147. package/dist/tools/conftest/pull.js +24 -10
  148. package/dist/tools/conftest/pull.js.map +1 -1
  149. package/dist/tools/conftest/push.d.ts.map +1 -1
  150. package/dist/tools/conftest/push.js +17 -7
  151. package/dist/tools/conftest/push.js.map +1 -1
  152. package/dist/tools/conftest/test.d.ts +10 -6
  153. package/dist/tools/conftest/test.d.ts.map +1 -1
  154. package/dist/tools/conftest/test.js +61 -39
  155. package/dist/tools/conftest/test.js.map +1 -1
  156. package/dist/tools/conftest/verify.d.ts +10 -6
  157. package/dist/tools/conftest/verify.d.ts.map +1 -1
  158. package/dist/tools/conftest/verify.js +40 -32
  159. package/dist/tools/conftest/verify.js.map +1 -1
  160. package/dist/tools/evaluation/_shared.js +9 -12
  161. package/dist/tools/evaluation/_shared.js.map +1 -1
  162. package/dist/tools/evaluation/bench.d.ts +29 -2
  163. package/dist/tools/evaluation/bench.d.ts.map +1 -1
  164. package/dist/tools/evaluation/bench.js +53 -9
  165. package/dist/tools/evaluation/bench.js.map +1 -1
  166. package/dist/tools/evaluation/compile.js +4 -4
  167. package/dist/tools/evaluation/compile.js.map +1 -1
  168. package/dist/tools/evaluation/eval.d.ts.map +1 -1
  169. package/dist/tools/evaluation/eval.js +12 -16
  170. package/dist/tools/evaluation/eval.js.map +1 -1
  171. package/dist/tools/evaluation/exec.d.ts +16 -0
  172. package/dist/tools/evaluation/exec.d.ts.map +1 -1
  173. package/dist/tools/evaluation/exec.js +38 -6
  174. package/dist/tools/evaluation/exec.js.map +1 -1
  175. package/dist/tools/evaluation/test-multiroot.d.ts +6 -0
  176. package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
  177. package/dist/tools/evaluation/test-multiroot.js +35 -8
  178. package/dist/tools/evaluation/test-multiroot.js.map +1 -1
  179. package/dist/tools/evaluation/test.d.ts +45 -0
  180. package/dist/tools/evaluation/test.d.ts.map +1 -1
  181. package/dist/tools/evaluation/test.js +153 -32
  182. package/dist/tools/evaluation/test.js.map +1 -1
  183. package/dist/tools/helpers/coverage-gaps.d.ts +11 -3
  184. package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -1
  185. package/dist/tools/helpers/coverage-gaps.js +7 -7
  186. package/dist/tools/helpers/coverage-gaps.js.map +1 -1
  187. package/dist/tools/helpers/describe-policy.d.ts.map +1 -1
  188. package/dist/tools/helpers/describe-policy.js +2 -2
  189. package/dist/tools/helpers/describe-policy.js.map +1 -1
  190. package/dist/tools/helpers/explain-decision.d.ts.map +1 -1
  191. package/dist/tools/helpers/explain-decision.js +3 -4
  192. package/dist/tools/helpers/explain-decision.js.map +1 -1
  193. package/dist/tools/helpers/explain-undefined.d.ts +9 -3
  194. package/dist/tools/helpers/explain-undefined.d.ts.map +1 -1
  195. package/dist/tools/helpers/explain-undefined.js +214 -73
  196. package/dist/tools/helpers/explain-undefined.js.map +1 -1
  197. package/dist/tools/helpers/fix.d.ts +11 -5
  198. package/dist/tools/helpers/fix.d.ts.map +1 -1
  199. package/dist/tools/helpers/fix.js +88 -45
  200. package/dist/tools/helpers/fix.js.map +1 -1
  201. package/dist/tools/helpers/generate-test-skeleton.d.ts.map +1 -1
  202. package/dist/tools/helpers/generate-test-skeleton.js +105 -21
  203. package/dist/tools/helpers/generate-test-skeleton.js.map +1 -1
  204. package/dist/tools/helpers/playground-share.d.ts +4 -2
  205. package/dist/tools/helpers/playground-share.d.ts.map +1 -1
  206. package/dist/tools/helpers/playground-share.js +13 -3
  207. package/dist/tools/helpers/playground-share.js.map +1 -1
  208. package/dist/tools/helpers/policy-diff.d.ts.map +1 -1
  209. package/dist/tools/helpers/policy-diff.js +3 -4
  210. package/dist/tools/helpers/policy-diff.js.map +1 -1
  211. package/dist/tools/helpers/security-audit.d.ts.map +1 -1
  212. package/dist/tools/helpers/security-audit.js +19 -19
  213. package/dist/tools/helpers/security-audit.js.map +1 -1
  214. package/dist/tools/helpers/verify.d.ts.map +1 -1
  215. package/dist/tools/helpers/verify.js +5 -1
  216. package/dist/tools/helpers/verify.js.map +1 -1
  217. package/dist/tools/meta/index.d.ts +1 -1
  218. package/dist/tools/server-management/_shared.d.ts +15 -4
  219. package/dist/tools/server-management/_shared.d.ts.map +1 -1
  220. package/dist/tools/server-management/_shared.js +86 -13
  221. package/dist/tools/server-management/_shared.js.map +1 -1
  222. package/dist/tools/server-management/data.d.ts.map +1 -1
  223. package/dist/tools/server-management/data.js +88 -23
  224. package/dist/tools/server-management/data.js.map +1 -1
  225. package/dist/tools/server-management/decisions.d.ts.map +1 -1
  226. package/dist/tools/server-management/decisions.js +16 -3
  227. package/dist/tools/server-management/decisions.js.map +1 -1
  228. package/dist/tools/server-management/policies.d.ts.map +1 -1
  229. package/dist/tools/server-management/policies.js +44 -7
  230. package/dist/tools/server-management/policies.js.map +1 -1
  231. package/dist/tools/server-management/status.d.ts.map +1 -1
  232. package/dist/tools/server-management/status.js +80 -13
  233. package/dist/tools/server-management/status.js.map +1 -1
  234. package/dist/types.d.ts +10 -1
  235. package/dist/types.d.ts.map +1 -1
  236. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -17,6 +17,577 @@ not part of the public surface and may change in minor releases.
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
+ ## [0.6.0] - 2026-09-07
21
+
22
+ ### Security
23
+
24
+ - `rego_playground_share` created public Gists, listed on the account and
25
+ searchable, while the README described them as secret. Anyone who shared a
26
+ policy with it should assume the policy was public from the moment it was
27
+ posted. Gists are now secret unless `public: true` is passed: reachable by
28
+ their link, listed nowhere. The change is not retroactive: GitHub cannot make
29
+ an existing Gist secret, so a Gist created earlier that should not have been
30
+ public has to be deleted at github.com/gists and shared again.
31
+
32
+ ### Changed
33
+
34
+ - `rego_bench` reports `iterations`, `nsPerOp`, `allocsPerOp` and
35
+ `bytesPerOp`, whole numbers as opa's own summary prints them, and keeps the
36
+ document opa printed under `raw` for a single run. Its fields `N`, `T`,
37
+ `Bytes`, `MemAllocs`, `MemBytes` and `Extra` were top-level before and now
38
+ sit under `raw`; the type had promised `iterations` and `metrics`, which
39
+ were never set. With `count` above one, `runs` holds every document and
40
+ `fastest` indexes the one the figures come from, so none is repeated.
41
+
42
+ ### Added
43
+
44
+ - `rego_capabilities` takes a `builtins` filter of up to 100 names and returns
45
+ their full records under `builtins`, with a `matched` count and the
46
+ `missing` names. When the records would not fit the response cap it returns
47
+ `OUTPUT_TOO_LARGE` rather than a truncated result, and `names_only: true`
48
+ alongside it is refused as a contradiction; `names_only: false`
49
+ returns every record and is documented as needing the cap raised.
50
+
51
+ ### Fixed
52
+
53
+ - Windows: a Rego module on a different drive from the server's working
54
+ directory was reported missing. The 0.5.0 drive-letter fix respelled data
55
+ documents relative to a working directory on their drive but left modules
56
+ absolute, since a module mounts at its own `package` whatever path it
57
+ arrives by. OPA still opens the module by the remainder after the colon, a
58
+ root-relative path it resolves against the drive the child is running on, so
59
+ a module on any other drive failed with a file-not-found. Every load path now
60
+ takes part in choosing the working directory; only data documents are
61
+ respelled.
62
+ - Windows: `rego_check` with inline source and `rego_inspect` reported a
63
+ module missing when the server's temp directory was on a different drive
64
+ from its working directory, and `conftest_test` and `conftest_verify` failed
65
+ the same way through `--policy`. OPA and conftest open an absolute path by
66
+ the part after its first colon, resolved on the drive the process runs on;
67
+ each command now runs from the path's own drive. The configs under test are
68
+ read by conftest itself and may sit on any drive; a policy and a data
69
+ directory spread across two drives are refused with a message saying so.
70
+ - The subprocess timeout is now hard on Linux and macOS. The SIGKILL escalation
71
+ fired on a flag Node sets when a signal is sent rather than when the child
72
+ ends, so a child that ignored SIGTERM hung the tool call for good, and a
73
+ wrapper script that left a grandchild holding the pipes kept the result from
74
+ ever settling. A child killed from outside the server is reported as
75
+ `SUBPROCESS_KILLED` naming the signal, not as a missing binary. On SIGINT or
76
+ SIGTERM the server now signals the children it started before exiting.
77
+ - `rego_eval`, `rego_eval_with_explain`, `rego_eval_with_profile`,
78
+ `rego_eval_with_coverage`, `rego_compile_query`, `rego_explain_decision`: a
79
+ string input that happened to parse as JSON, such as `"42"`, `"true"` or a
80
+ quoted string, was retyped or unwrapped before evaluation. Strings now reach
81
+ the policy as strings; only an object or array that arrived serialized as a
82
+ string is still repaired, the way `rego_bench` and the server-management
83
+ tools already did.
84
+ - `rego_fix`: a real run reported zero fixes and no changed files after
85
+ changing them, because only the dry-run wording of regal's summary was read.
86
+ Both forms are read now.
87
+ - `opa_*` server tools: a request that OPA did not answer within
88
+ `OPA_MCP_HTTP_TIMEOUT_MS` was reported as `OPA_UNREACHABLE`, with a hint to
89
+ start a server that was already running. It is now `TIMEOUT`, naming the
90
+ limit, and the timer covers the response body as well as the headers.
91
+ - `conftest_test`: a denial reported under `failOnWarn` came back as a tool
92
+ error rather than as a failed check, because conftest exits 2 for it. Any
93
+ exit code with results on stdout is now an outcome, and only output without
94
+ results is treated as a command error, whose message now carries conftest's
95
+ own text; `conftest_verify` shares that last part.
96
+ - `rego_verify`: a policy that exhausted the Z3 WASM heap took the whole
97
+ server down, since the abort surfaced outside every try/catch. The solver is
98
+ now bounded at 768 MB, under a 1 GiB ceiling on Z3's allocations, so an
99
+ oversized problem comes back inconclusive.
100
+ - `rego_verify`: a helper whose body contains a literal `false` was inlined as
101
+ an always-true body, so a rule that can never fire was reported proven always
102
+ true, and a negated literal (`not false`, `not true`) was read as the bare
103
+ one in helpers and rule bodies alike. Boolean literals are now read as what
104
+ they say, and a helper with a true default and a body that never holds is
105
+ recognised as always holding.
106
+ - Every tool that evaluates Rego, including the Regal tools that run a
107
+ project's custom rules, now declares `openWorldHint: true` and no longer
108
+ claims `readOnlyHint`, since a policy's own `http.send` can reach, and write
109
+ to, a remote system. A client that gates on the hints will ask before running
110
+ one. The destructive and idempotent hints on those tools are left to the
111
+ spec's defaults, since a policy chooses its own HTTP method.
112
+ - Docker: the `opa` and `regal` downloads in the image build are now checked
113
+ against the digests published with their releases. The image was described
114
+ as reproducible while nothing verified those downloads; the wording now says
115
+ what the build does.
116
+ - `rego_security_audit` was described as running regal's `security` and
117
+ `bugs` categories; regal ships no `security` category, so that half of the
118
+ sweep matched nothing. The description now says what runs: the `bugs`
119
+ category, plus any custom rules a project places in a `security` category.
120
+ - `rego_explain_undefined`: on the path where OPA's indexer skips the rule, the
121
+ blocking condition was chosen from each body expression evaluated on its own,
122
+ so an expression that needs an earlier local or a sibling rule came back
123
+ unevaluable and was blamed ahead of the guard that really failed. The body is
124
+ now evaluated as cumulative prefixes inside the rule's package, with its
125
+ imports, and the first condition that stops holding is the one reported; the
126
+ conditions after it are left unevaluated, as on the traced path.
127
+ - `rego_check_schema` reported `valid: true` when `schemaPath` was a
128
+ directory, since opa reads a schema directory only through `schemas:`
129
+ annotations in the policy. A directory is now accepted when the policy
130
+ carries them (read from the source, or reported by `opa inspect` for files
131
+ on disk) and refused before opa runs when it does not, with the file form,
132
+ `inlineSchema` and the annotation named as the ways to make it work.
133
+ - `opa_bundle_sign` reported `signed: true` for a `.tar.gz` archive after
134
+ writing a `.signatures.json` beside it, which OPA never reads, so the
135
+ archive stayed unsigned. An archive is now refused with a pointer to
136
+ `opa_bundle_build`, which produces a signed one. The `outputDir` input,
137
+ which only applied to archives, is gone.
138
+ - `OPA_MCP_MAX_RESPONSE_BYTES` now bounds error envelopes as well as
139
+ results. An oversize error was sent whole with `truncated: true` set; its
140
+ details are now dropped first and its message cut last, so the code and
141
+ the message stay readable within the cap.
142
+ The cap bounds a success envelope's warnings as well, and
143
+ `OPA_MCP_MAX_RESPONSE_BYTES` refuses a value below 512, which sits above
144
+ the smallest complete envelope, rather than exceeding it.
145
+ - The temp directory inline source is written to could appear in the error
146
+ details of a dozen tools, in the message a binary printed about the file.
147
+ Every error envelope now passes through the sanitiser, which also covers a
148
+ JSON-encoded spelling, a directory name with a space, the inline schema and
149
+ bundle-verify temp files, and takes linear time on any input.
150
+ The server's own temp directory is matched by its exact spelling first,
151
+ so no guess about where a path begins is involved for the files it writes.
152
+ - `rego_explain_undefined` turned a spawn failure during its per-condition
153
+ evals or its parse step into a per-condition note or an empty analysis. A
154
+ binary that cannot run or a run that timed out now returns the tool's
155
+ `OPA_BINARY_NOT_FOUND` or `TIMEOUT` like every other tool.
156
+ - `rego_explain_undefined` validated `inputPath` and then passed the argument
157
+ as written to opa instead of the resolved path.
158
+ - The `*_BINARY` variables now refuse a relative path at startup, which the
159
+ README said they did, a drive-relative or root-relative name included; a
160
+ bare command name or an absolute path is accepted.
161
+ - Docs: the install note described a missing-`opa` failure that the npm
162
+ package's bundled binary already prevents, and now says where it still
163
+ applies; CONTRIBUTING said input fields are `snake_case` when the surface
164
+ is `camelCase`; two prompts sent readers to `rego_describe_policy` for input
165
+ refs, which `rego_infer_input_schema` reports.
166
+ - `rego_migrate_v1` reported a built-in that v1 removed, which fails type
167
+ checking in the `opa fmt --rego-v1` phase, as a parse failure with advice to
168
+ fix syntax. The type error opa gives is now the message, with a hint to
169
+ replace the built-in first; the description says so.
170
+ - `rego_verify`: a quoted key holding a dot, `input["a.b"]`, and the nested
171
+ path `input.a.b` were treated as one field, so a rule reading both was
172
+ proved never true, and a witness for the quoted key was built as the nested
173
+ object. Paths are now rendered the way Rego writes them and read back the
174
+ same way.
175
+ The soundness fuzz now carries quoted keys, so it exercises this.
176
+ - `conftest_test`, `conftest_verify`: an error from conftest named the temp
177
+ file an inline config or policy had been written to, a file the tool had
178
+ already removed. The path is replaced in stderr as it already was in the
179
+ results.
180
+ - `rego_verify`: a witness holding a non-ASCII string came back in Z3's
181
+ escape text, one escape per byte, which OPA did not accept as the string
182
+ the policy compares against. The escapes are decoded now. A backslash in a
183
+ policy literal is escaped on the way into Z3, so a literal that spells such
184
+ an escape itself is no longer read as one.
185
+ - Docs: the README now says an argument that fails a tool's input schema is
186
+ rejected by the MCP layer before the handler runs, names `rego_verify`'s
187
+ `kind` field, and describes `rego_suggest_fix` as returning suggestions with
188
+ a confidence level; the `opa://builtins` resource says which `opa` binary
189
+ it reflects.
190
+ - `rego_verify`: a field compared as a string, number or boolean and also read
191
+ as the object holding a deeper field was modelled as two unrelated values,
192
+ so a rule no input can satisfy was reported satisfiable with a witness OPA
193
+ rejects. The solver now knows that a field the rule compared equal to a
194
+ scalar, or fed to a string built-in, is never present alongside a path
195
+ beneath it. A rule that compares such a field in any other way (an
196
+ inequality, an ordering, a bare read, a comparison against another field)
197
+ and also reads beneath it is reported inconclusive, since the model gives
198
+ the field one scalar value that no input holding the deeper field can
199
+ match; before, that produced a counterexample OPA rejects. Both readings
200
+ are taken from the rule under test alone, so another rule in the module
201
+ does not decide either.
202
+ - `rego_verify` built its witness from every input path in the policy, so a
203
+ field only another rule reads was given a value and placed in the input.
204
+ Where that field was the parent of one the rule under test reads, the two
205
+ collided and the witness no longer satisfied the rule: `allow if input.x.y
206
+ == 2` beside `other if input.x > 1` returned `{"x": 0}`, which the policy
207
+ evaluates to undefined, and reported it as proof the rule can be true. A
208
+ witness now names only the fields its own rule reads. The witness
209
+ search that prefers every field present also re-checks after backing out,
210
+ rather than reading a stale model.
211
+ - `rego_test` with `coverage` or `threshold` and `count` above 1 returned no
212
+ coverage and reported the threshold as met: opa prints one report per
213
+ repetition and the concatenation did not parse as JSON, so none was read.
214
+ One is read now.
215
+ - `rego_test_multiroot` in coverage mode reported a root holding a `todo_`
216
+ test as failed and dropped its report, as `rego_test` used to; the report is
217
+ kept and the root passes.
218
+ - `rego_generate_test_skeleton` referenced every rule the same way, so a
219
+ function rule made the generated file fail to compile and a set, object or
220
+ value rule was compared to `true`. Each stub now follows the rule's head: a
221
+ function is called with placeholder arguments, a set or object is compared
222
+ to an empty one, a value rule to its literal when the head is one; a
223
+ computed head, which offers nothing to assert, becomes a `todo_test_` that
224
+ opa test skips rather than a placeholder that passes. The generated file no longer
225
+ imports the package it references by full path, which `opa check --strict`
226
+ reported as an unused import.
227
+ - A username and password embedded in `OPA_URL` were echoed into every
228
+ `opa_*` error envelope and the startup log, and made every call fail as
229
+ `OPA_UNREACHABLE`, since the HTTP client refuses such a URL. They are now
230
+ redacted wherever the URL is shown, and such a URL is refused with
231
+ `OPA_URL_INVALID` and a hint to use `OPA_TOKEN`.
232
+ Only the credentials are removed from the URL shown; its case, port and
233
+ path stay as the operator wrote them.
234
+ - `rego_verify` never gave the Z3 engine's memory back: its solver and
235
+ model were left to the JavaScript collector, which cannot see Z3's heap and
236
+ so had no reason to run, and the engine grew by half to one megabyte per
237
+ solve until its ceiling, between 600 MB and 1.7 GB over 1500 solves in the
238
+ same process depending on the run, with verdicts degrading to inconclusive
239
+ along the way. The solver is released as each solve ends, and its model
240
+ with it; 1500 solves now hold at about 210 MB.
241
+ - `rego_verify` could fault Z3 intermittently, which disabled verification
242
+ until the server restarted: z3-solver frees its objects from finalizers on
243
+ the main thread while a solve runs on a worker over the same shared
244
+ memory, and one landing mid-solve corrupted the heap. Finalizers are now
245
+ held while a solve runs, and a fault brings up a fresh Z3 on the next call,
246
+ three times per process, with the interrupted call retried once.
247
+ - The server reported itself as 0.4.0 on the 0.5.0 release, in the MCP
248
+ handshake, `mcp_server_info`, `--version` and the startup log: the version
249
+ was a constant kept apart from package.json. It is now read from
250
+ package.json, a test holds package.json, manifest.json and server.json to
251
+ one version, and a release stops before publishing when its tag names a
252
+ version package.json does not carry.
253
+ - The startup warning and hint for a missing `regal` named `rego_lint` alone;
254
+ `rego_security_audit` and `rego_fix` need it too, and the manifest, the
255
+ registry entry and the Smithery config say so now. `--help` lists
256
+ `OPA_MCP_BLOCK_ENV`. `conftest_verify` said an omitted `namespace` both
257
+ defaulted to `main` and verified all namespaces; it verifies all.
258
+ `rego_check_schema` and `rego_playground_share` describe the schema
259
+ directory form and the `public` field they already had.
260
+
261
+ ## [0.5.0] - 2026-09-04
262
+
263
+ ### Security
264
+
265
+ - `opa_config` described its output as sanitized with secrets excluded. OPA
266
+ drops the `credentials` block from `GET /v1/config` but returns
267
+ `services.*.headers` verbatim, and a header is the ordinary place to put an
268
+ API key or a bearer token for a bundle service, so a live credential was
269
+ handed to whatever agent called the tool. `opa_status` returns the same
270
+ document and had the same exposure. Header values are now replaced with a
271
+ marker and the header names kept, so the document still says what the server
272
+ is configured to send.
273
+ - `rego_verify` returned `proven` and `unsatisfiable` for claims that are false,
274
+ on ordinary policy shapes, and reported no unsupported constructs while doing
275
+ it, so nothing distinguished a real proof from a wrong one. A `proven` verdict
276
+ was not usable as evidence that a policy cannot be bypassed. Every released
277
+ version is affected. Five causes, each enough on its own: clauses whose head
278
+ shape the encoder does not support were dropped rather than reported, and a
279
+ rule with every clause dropped encoded to an empty body, which is vacuously
280
+ true; head values were discarded, so `allow := false if { ... }` was encoded as
281
+ though the head were true; `default` was not encoded at all, so
282
+ `default allow := true` with a non-matching body answered `never_true`; input
283
+ references were modelled as always present, so a body reading `input.x` was
284
+ treated as defined when `x` is absent; and locals were scoped by clause index
285
+ alone, so a helper and its caller sharing a variable name collapsed into one
286
+ symbol. Encoding now fails closed: a clause holding anything the encoder cannot
287
+ represent makes the verdict `inconclusive` rather than silently shrinking the
288
+ formula. That costs coverage, and about one generated policy in sixteen now
289
+ answers `inconclusive` where it previously gave a confident wrong answer.
290
+ Numbers encode as reals rather than integers, so `input.n > 0` with
291
+ `input.n < 1` is satisfiable at 0.5 instead of being falsely refuted.
292
+ Verification also ran without a mutex on the shared solver context.
293
+ - `conftest_test` joined the `inlineConfigParser` value into the temp file name
294
+ for inline config without checking it, so a value carrying `../` segments
295
+ placed the inline config, whose content the caller also chooses, at any path
296
+ the server could write. Parser names are now a closed set (conftest 0.69's
297
+ nineteen), enforced in the schema and again in the handler, and the parser is
298
+ passed to conftest explicitly rather than through the file name.
299
+ - Path validation followed links only for paths that already existed, so a
300
+ write destination that did not exist yet, such as an `opa_bundle_build` output
301
+ or a `conftest_pull` policy directory, was accepted on its spelling alone. A
302
+ junction or symbolic link inside an allowed root that pointed outside it made
303
+ such a write land outside the roots. A path is now judged by the real location
304
+ of its nearest existing ancestor with the missing segments re-attached, a
305
+ dangling link is refused, and roots and paths are compared in canonical form,
306
+ which also ends false rejections for a root spelled through a link (macOS
307
+ `/var`), a Windows short name, or a different letter case.
308
+ - `conftest_pull` and `conftest_push` skipped the allow-list entirely when
309
+ `policy` was omitted. Both tools document that the policy directory must sit
310
+ inside `OPA_MCP_ALLOWED_PATHS`, but the omitted case fell through to the
311
+ conftest default, resolved against the working directory of the server:
312
+ `conftest_pull` wrote policy files there, outside any allowed root. The
313
+ default is now resolved and checked like an explicit path, and refused with
314
+ `PATH_NOT_ALLOWED` when it falls outside.
315
+ - `opa_bundle_sign` wrote `.signatures.json` into the server's working directory,
316
+ outside `OPA_MCP_ALLOWED_PATHS`, and reported `signed: true` while the bundle it
317
+ was asked to sign stayed unsigned. `opa sign` puts the file wherever
318
+ `--output-file-path` says, that flag defaults to the process cwd, and it was
319
+ not being passed. A directory bundle is now signed in place and an archive
320
+ beside itself (or in `outputDir`), both validated like every other path the
321
+ server writes, and success is reported only after the file is observed on
322
+ disk. A `.signatures.json` already present as a symbolic link is refused
323
+ rather than written through. The response carries the path written, the
324
+ algorithm, and the number of files covered.
325
+
326
+ ### Fixed
327
+
328
+ Results that were wrong without saying so:
329
+
330
+ - The five OPA data tools read a key containing a dot as two path segments and
331
+ returned a different document than the one asked for, with nothing to signal
332
+ the substitution. `opa_get_data` on `hosts/example.com` fetched
333
+ `/v1/data/hosts/example/com`; the same substitution applied to
334
+ `opa_put_data`, `opa_patch_data`, `opa_delete_data` and `opa_query_decision`,
335
+ so a write or a delete could land on the wrong document. A path containing a
336
+ slash now treats slash as its only separator, and a path without one is read
337
+ as dotted. Segments are percent-encoded: a key holding `?` or `#` truncated
338
+ the request URL at that character and read the parent document, and keys
339
+ holding a space, a percent sign or non-ASCII characters were unreachable.
340
+ - `opa_patch_data` documented an empty path for patching the root of the data
341
+ hierarchy, but the schema required at least one character and the path it
342
+ built for the root is one OPA answers with a redirect. Omitting both `path`
343
+ and `segments` now patches the root.
344
+ - `opa_exec` did not evaluate the rule it was asked for. Its `decision`
345
+ description told callers to pass a fully-qualified Rego reference such as
346
+ `data.authz.allow`, but `opa exec --decision` names a decision by
347
+ slash-separated path with no `data.` prefix. Any other spelling is accepted by
348
+ the flag and resolves to nothing, so every input file came back with
349
+ `opa_undefined_error`, which under a `deny`-style policy reads as a clean
350
+ pass. Both spellings are now converted to the path OPA expects, and a
351
+ reference with nothing left to name is rejected as `INVALID_INPUT`.
352
+ - `rego_test` and `rego_test_multiroot` counted a test OPA could not evaluate as
353
+ a passing test. OPA marks such a record with an `error` object and does not set
354
+ `fail`, so deriving the pass count as `total - failed - skipped` absorbed it,
355
+ and a suite whose tests all raised (a rule conflict, for instance) was reported
356
+ as fully passing with zero failures. Both tools now report `errored`
357
+ separately, and the multiroot aggregate carries `totalErrored`.
358
+ - Windows: a data document passed by absolute path was loaded under its drive
359
+ letter instead of where the policy expected it. OPA reads every load path as
360
+ an optional `prefix:path` pair and splits on the first colon, so
361
+ `C:\policies\data.json` mounted at `data.C` and a rule reading `data.tier`
362
+ found nothing, while the tool reported success. `opa test` on a suite whose
363
+ tests read data reported those tests as failing. Load paths are now passed
364
+ relative to a directory the `opa` process runs in, which is the only spelling
365
+ OPA reads correctly. Rego modules are unaffected either way, because a module
366
+ mounts at its own `package` rather than at its path, which is why policies
367
+ worked and only their data did not. Nothing changes on macOS or Linux, whose
368
+ absolute paths carry no drive letter. Load paths spanning two drives are now
369
+ reported as an error, since OPA cannot load documents from two drives in one
370
+ invocation.
371
+ - The ABAC example in the `opa://patterns` resource failed to evaluate on the
372
+ case it exists to handle. It expressed "hide secret resources from other
373
+ organizations" as a second rule assigning `allow := false`, which in Rego is a
374
+ conflict rather than an override: a user reading their own secret resource
375
+ from another organization got `eval_conflict_error` instead of a denial. The
376
+ denial is now a condition the permissive rules consult. The pitfalls list,
377
+ which recommended the broken form, says why it does not work.
378
+ - The Terraform example in the `opa://patterns` resource did not reject a
379
+ full-admin IAM policy. It tested `"*" in statement.Action`, which requires
380
+ `Action` to be a collection, and AWS accepts a bare string there, in
381
+ `Resource`, and for `Statement` itself. Of the four ways to spell
382
+ `Allow * on *`, the rule caught one; the most common form,
383
+ `{"Action": "*", "Resource": "*"}`, was allowed. Each position is now widened
384
+ to a set before the wildcard test. Scoped policies and `Deny` statements are
385
+ still allowed, so the rule has not become indiscriminate.
386
+ - `rego_test` with `coverage` or `threshold` reported `One or more tests
387
+ failed` for a suite where none did. A suite holding a `todo_` test exits
388
+ non-zero under `--coverage` with an empty stderr, and the coverage report is
389
+ on stdout as asked for. The report was discarded and the run called a
390
+ failure. A non-zero exit with a parseable report and no failure lines is now
391
+ the coverage result it is, and a report OPA did produce is kept in the error
392
+ details when tests really did fail.
393
+ - `rego_coverage_gaps` reported `testsPassed`, `testsFailed` and
394
+ `testsSkipped` as zero on every call. OPA emits no per-test records in
395
+ coverage mode, so the three counts could never be anything else, and three
396
+ zeros read as "no tests ran" rather than "not reported". They are now
397
+ omitted unless OPA supplied records.
398
+ - `opa_health` reported a reachable server as `OPA_UNREACHABLE`. A server that
399
+ answers `/health?bundles=true` with `one or more bundles are not activated`
400
+ is running; the caller was told no server was found and to go start one, and
401
+ OPA's own reason was buried in a stringified error. Such a response is now a
402
+ result, `healthy: false` with `reason`. A 401 maps to `OPA_AUTH_FAILED`, and
403
+ `OPA_UNREACHABLE` is left for a server that could not be reached.
404
+
405
+ Tools that did not work as documented:
406
+
407
+ - `opa_bundle_verify` passed `--verification-key` to `opa eval`, which has no
408
+ such flag, so verification always failed with "unknown flag" and was reported
409
+ as `INVALID_BUNDLE`, signed or not. Verification now runs through
410
+ `opa build --verification-key` into a discarded temp file, which is the path
411
+ OPA provides. Failures carry `details.reason`: `signature_invalid`,
412
+ `scope_mismatch`, `file_modified`, `file_added`, `file_missing`,
413
+ `file_unparseable`, `unsigned`, `signatures_malformed`, `not_a_bundle`,
414
+ `bundle_load_error`, or `unknown` when OPA's message is not recognised. A key
415
+ or algorithm OPA cannot use is reported as `INVALID_INPUT` by both tools.
416
+ - Directory bundles are signed and verified by name from the parent directory,
417
+ the way `opa sign --bundle <name>` records them, so a signed directory stays
418
+ valid wherever it is placed under that name and a directory signed with the
419
+ OPA CLI verifies. A symbolic link or junction given as the bundle is resolved
420
+ first; OPA does not descend a linked root and would sign an empty file list.
421
+ - `opa_bundle_build` passed `--signing-key` and `--verification-key` without
422
+ `--bundle`, which `opa build` refuses, so neither option worked unless
423
+ `bundle: true` was also set. Either option now implies bundle mode.
424
+ - `opa_bundle_sign` returned an empty `stderr` on failure because `opa sign`
425
+ prints its errors on stdout. `details` now carries both streams.
426
+ - `conftest_test` and `conftest_verify` threw `UNKNOWN_ERROR` on every clean run.
427
+ conftest omits every empty array from its JSON, so a passing file arrives with
428
+ no `failures` key and the summary code dereferenced it. Results now always
429
+ carry their arrays, `conftest_verify` reports `NO_TESTS_FOUND` for a policy
430
+ directory with no test rules (conftest prints `null` there), and both
431
+ summaries count files by name, since conftest emits one entry per namespace
432
+ or per test rule. `summary.successes` and `summary.failures` are added to
433
+ `conftest_test`. `exceptions` are messages, not strings, matching conftest.
434
+ - `conftest_pull` did not write to the directory it was given. Conftest resolves
435
+ `--policy` against the working directory rather than honouring an absolute
436
+ path, and the tool resolves the caller's path against the allow-list before
437
+ handing it over, so the path was always absolute. On Windows the pull failed
438
+ outright, reporting a path of the form `.\C:\...`. `conftest_push` had the
439
+ same handling and read from the same path on whichever drive it happened to
440
+ start on. Both now run from the parent directory and name the target
441
+ relatively.
442
+ - `rego_test` with `count` above 1 reported the suite as having no tests. OPA
443
+ prints one pretty-printed JSON array per repetition, back to back, which is
444
+ neither a single JSON value nor one record per line, so nothing parsed and the
445
+ tool returned `NO_TESTS_FOUND` for a suite that had just run. The repetitions
446
+ are now read and collapsed to one record per test carrying its worst outcome,
447
+ so a test that fails intermittently is reported as failing.
448
+ - `rego_test` did not populate `parameterizedGroups`. OPA reports a
449
+ `test_x[case]` rule as a single record carrying the per-case outcomes in
450
+ `sub_results`, not as one record per case, so looking for a bracketed test
451
+ name found nothing on any OPA 1.x run. A rule whose cases mostly passed was
452
+ reported as one failing test with no indication of which case failed. The
453
+ cases are now grouped under the rule name, and the bracketed form older
454
+ versions emitted is still read.
455
+ - `rego_bench` failed with `UNKNOWN_ERROR` for any `count` above 1. OPA prints
456
+ one JSON document per repetition, back to back, which is not a single JSON
457
+ value, so nothing parsed. Every repetition is now returned in `runs`, and the
458
+ top-level figures come from the fastest of them per iteration.
459
+ - `rego_bench` reported a failed benchmark with an empty error. `opa bench
460
+ --format=json` writes its diagnostics to stdout as an `errors` array and
461
+ leaves stderr empty, and the tool reported only stderr, so a query with a
462
+ syntax error came back as `EVAL_ERROR` with nothing in it. The diagnostics
463
+ are now included.
464
+ - `opa_list_policies` returned nothing but a truncation notice on a server
465
+ holding more than a couple of dozen policies. OPA answers the policy
466
+ endpoints with each policy's parsed AST alongside its source, and the AST is
467
+ far larger than the text it came from, so the response passed
468
+ `OPA_MCP_MAX_RESPONSE_BYTES` and the payload was replaced with advice to
469
+ narrow the scope. The tool took no arguments, so there was no scope to
470
+ narrow. It now returns the policy IDs and a count, with `includeSource` and
471
+ `includeAst` to ask for more.
472
+ - `opa_get_policy` returned the AST alongside the source, which nothing had
473
+ asked for: a 477-byte policy came back as a 19 KB response. The AST is now
474
+ behind `includeAst`.
475
+ - The server did nothing when it was reached through a symbolic link. Its
476
+ entry-point check compared `import.meta.url` with `process.argv[1]` as
477
+ strings, and Node resolves symlinks for a module's own URL while leaving
478
+ `argv[1]` as it was invoked, so the two differed and neither the CLI flags nor
479
+ the transport ran: the process started and exited in silence. npm's `bin`
480
+ entry is a symlink on macOS and Linux. The comparison is now between real
481
+ paths, so how the file was reached no longer matters.
482
+ - `rego_explain_undefined` had nothing to say about a policy written with
483
+ `default allow := false`. A default gives the query a value, so it is never
484
+ undefined and the tool returned that value and stopped, skipping the
485
+ per-clause analysis it exists for. A query whose value came from a default
486
+ and from nothing else is now analysed, and `queryResult` reports `default`.
487
+ - Clauses of a multi-clause rule were not told apart in the trace. OPA leaves
488
+ `Node.location` unset on trace events, so the row comparison meant to
489
+ distinguish them always fell through to matching on the rule name, and every
490
+ clause looked present in the trace as soon as one was. Those clauses were
491
+ never evaluated standalone: each came back with every condition
492
+ `unevaluable` and no blocking condition. The event's own location is now
493
+ used.
494
+ - `rego_lint`, `rego_fix` and `rego_security_audit` ignored the linted project's
495
+ own `.regal/config.yaml`, and applied any configuration sitting above the
496
+ server's working directory to every call instead. Regal discovers its
497
+ configuration by walking up from its own working directory rather than from
498
+ the files it is given, and it was spawned without one, so it inherited the
499
+ server's, which for a stdio server is wherever the client launched it. Rules a
500
+ project had turned off were reported anyway, and inline source, which belongs
501
+ to no project, picked up whatever happened to be above the server. Regal now
502
+ runs in the directory of what it is linting, and inline source runs in its own
503
+ temp directory. An explicit `configFile` still takes precedence.
504
+
505
+ Configuration and environment:
506
+
507
+ - An empty or blank environment variable was treated as a real value.
508
+ `OPA_BINARY=""`, which is what a shell leaves behind when it expands an
509
+ unset variable, is not the literal default `opa`, so binary resolution
510
+ skipped the bundled build and every `rego_*` call tried to spawn nothing.
511
+ Blank now means unset for every variable the server reads, and values are
512
+ trimmed.
513
+ - `OPA_MCP_TIMEOUT_MS` and `OPA_MCP_HTTP_TIMEOUT_MS` accepted values Node
514
+ cannot represent. A timer of 2147483648 ms or more is clamped to 1 ms with
515
+ only a process warning, so a large value set to mean "effectively no
516
+ timeout" timed out every subprocess and every HTTP call immediately. Values
517
+ above 2147483647 are now refused at startup with a message saying why.
518
+ - An `install-id` file that existed but held no id was a permanent trap. The
519
+ read found no id, the exclusive create failed because the file was there, and
520
+ the fallback read found no id again, on every run for the life of the machine.
521
+ The file is now rewritten when it holds no usable id; a brand-new file is
522
+ still created exclusively so two first runs cannot both claim it. A file can
523
+ end up empty after a crash or a full disk during the first run.
524
+ - The test suites no longer emit telemetry pings.
525
+
526
+ ### Added
527
+
528
+ - `opa_bundle_sign` accepts `outputDir` for archives, the directory that
529
+ receives `.signatures.json`. A directory bundle is always signed in place,
530
+ since OPA only reads the signature from inside the bundle.
531
+ - `opa_bundle_verify` accepts `v0Compatible` for bundles written in Rego v0,
532
+ which otherwise fail to load after the signature has been checked.
533
+ - The five OPA data tools accept `segments`, an array of literal key segments,
534
+ for keys that contain both a dot and a slash and so cannot be written as a
535
+ path string. `opa_put_data`, `opa_patch_data` and `opa_delete_data` return the
536
+ resolved `segments` alongside the `path` that was supplied.
537
+ - `opa_exec` output gains `hint`, present when every input left the decision
538
+ undefined. That is the expected outcome when no rule matched and also what a
539
+ decision naming nothing looks like, and the per-file results do not
540
+ distinguish them.
541
+ - `OPA_MCP_BLOCK_ENV` withholds named variables from `opa`, `regal` and
542
+ `conftest` even when they are on the built-in allow-list. It is applied last,
543
+ so it also overrides `OPA_MCP_PASSTHROUGH_ENV` and anything a command passes
544
+ explicitly. It exists so an operator behind an authenticated proxy can choose
545
+ to lose proxy support rather than expose those credentials to evaluated
546
+ policy.
547
+
548
+ ### Changed
549
+
550
+ - `rego_test` output gains `errored`, `repetitions` (present only when more
551
+ than one repetition ran; OPA stops repeating at the first run that fails, so
552
+ this can be lower than the requested `count`) and `caseCounts` (present only
553
+ when the run had a parameterized test; the top-level counts still follow OPA
554
+ and treat such a rule as one test however many cases it holds).
555
+ `rego_test_multiroot` gains `errored` per root and `totalErrored` overall.
556
+ - `opa_list_policies` output gains `count`.
557
+ - `rego_explain_undefined` output: `queryResult` gains `default`, and `value`
558
+ is populated for it. On a query that is genuinely defined the tool now also
559
+ runs `opa parse`, which is how it tells a default apart from a rule that
560
+ matched.
561
+ - `OPA_MCP_ALLOWED_PATHS` now refuses a relative entry, as documented. A
562
+ relative root was resolved against the server's working directory, so for a
563
+ stdio server the same configuration permitted different directories depending
564
+ on how the client launched it.
565
+ - `opa-mcp --help` lists `OPA_MCP_MAX_SUBPROCESS_BYTES`,
566
+ `OPA_MCP_PASSTHROUGH_ENV` and `OPA_MCP_NO_TELEMETRY`, which were documented
567
+ but absent from the output an invalid-configuration message points at.
568
+ - The 0.4.0 entry below, the README and the source comment all described the
569
+ child-process allow-list as containing no secret. It carries no cloud or
570
+ repository credential, but `HTTP_PROXY`, `HTTPS_PROXY` and `ALL_PROXY` are on
571
+ it and a proxy URL can embed a username and password, which any evaluated
572
+ policy can read through `opa.runtime().env`. All three now say so. No
573
+ behaviour changed; the exposure was there in 0.4.0 as shipped and is
574
+ unchanged by this correction.
575
+ - Documentation corrected where it did not match the tools: `opa_status`
576
+ returns `GET /v1/config`, not bundle or decision-log status;
577
+ `rego_describe_policy` does not report input references, so the two prompts
578
+ that told the model to use it for that now name `rego_infer_input_schema`;
579
+ `rego_lint` returns a flat list of violations rather than findings grouped by
580
+ category; `rego_capabilities` reflects the resolved `opa` binary rather than
581
+ the bundled one; `rego_explain_decision` returns a structured summary rather
582
+ than a natural-language explanation, and the extension manifest no longer
583
+ says the helper tools use AI; the MCPB bundle has no bundled-binary fallback;
584
+ unit tests run on macOS only on Node 22.
585
+ - Four error codes that nothing returns are no longer listed as codes a caller
586
+ can expect: `REGAL_VERSION_TOO_OLD`, `DEPENDENCY_CONFLICT`,
587
+ `VERIFY_INCONCLUSIVE` and `Z3_INIT_ERROR`. They remain reserved in the type.
588
+ The troubleshooting entry for a Regal minimum-version check that does not
589
+ exist is removed.
590
+
20
591
  ## [0.4.0] - 2026-09-03
21
592
 
22
593
  ### Security
@@ -29,9 +600,15 @@ not part of the public surface and may change in minor releases.
29
600
  `rego_eval` accepts inline source, so `OPA_MCP_ALLOWED_PATHS` never applied and no
30
601
  filesystem access was needed; a policy arriving through a README, an issue, or a
31
602
  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.
603
+ route to third-party policy. Children now get an explicit allow-list.
604
+ `OPA_MCP_PASSTHROUGH_ENV` opts individual variables back in, and anything named
605
+ there is readable by evaluated policy by design.
606
+
607
+ The allow-list carries no cloud or repository token, but it is not free of
608
+ credentials: `HTTP_PROXY`, `HTTPS_PROXY` and `ALL_PROXY` are on it, and a proxy
609
+ URL can embed a username and password, so an operator behind an authenticated
610
+ corporate proxy is still handing those to evaluated policy. They are on the list
611
+ because dropping them breaks proxied bundle downloads and `http.send`.
35
612
 
36
613
  On Windows, libuv copies a fixed set of variables to every child regardless of what
37
614
  is requested. `USERNAME`, `USERDOMAIN` and `LOGONSERVER` cannot be removed, so they
@@ -1028,7 +1605,9 @@ wrappers end-to-end. CI matrix: Ubuntu, macOS, and Windows on Node
1028
1605
  20 and 22, plus CodeQL security scanning and weekly Dependabot updates
1029
1606
  for npm, GitHub Actions, and Docker base images.
1030
1607
 
1031
- [Unreleased]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.4.0...HEAD
1608
+ [Unreleased]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.6.0...HEAD
1609
+ [0.6.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.5.0...v0.6.0
1610
+ [0.5.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.4.0...v0.5.0
1032
1611
  [0.4.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.3.0...v0.4.0
1033
1612
  [0.3.0]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.2.1...v0.3.0
1034
1613
  [0.2.1]: https://github.com/OrygnsCode/opa-mcp-server/compare/v0.2.0...v0.2.1