@orygn/opa-mcp 0.4.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.
- package/CHANGELOG.md +339 -3
- package/README.md +71 -72
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +57 -15
- package/dist/config.js.map +1 -1
- package/dist/lib/bundle-signatures.d.ts +23 -0
- package/dist/lib/bundle-signatures.d.ts.map +1 -0
- package/dist/lib/bundle-signatures.js +152 -0
- package/dist/lib/bundle-signatures.js.map +1 -0
- package/dist/lib/child-env.d.ts +9 -2
- package/dist/lib/child-env.d.ts.map +1 -1
- package/dist/lib/child-env.js +38 -6
- package/dist/lib/child-env.js.map +1 -1
- package/dist/lib/conftest-cli.d.ts +25 -10
- package/dist/lib/conftest-cli.d.ts.map +1 -1
- package/dist/lib/conftest-cli.js +152 -33
- package/dist/lib/conftest-cli.js.map +1 -1
- package/dist/lib/install-id.d.ts.map +1 -1
- package/dist/lib/install-id.js +18 -3
- package/dist/lib/install-id.js.map +1 -1
- package/dist/lib/json-stream.d.ts +26 -0
- package/dist/lib/json-stream.d.ts.map +1 -0
- package/dist/lib/json-stream.js +69 -0
- package/dist/lib/json-stream.js.map +1 -0
- package/dist/lib/opa-cli.d.ts +64 -16
- package/dist/lib/opa-cli.d.ts.map +1 -1
- package/dist/lib/opa-cli.js +98 -28
- package/dist/lib/opa-cli.js.map +1 -1
- package/dist/lib/opa-paths.d.ts +24 -0
- package/dist/lib/opa-paths.d.ts.map +1 -0
- package/dist/lib/opa-paths.js +97 -0
- package/dist/lib/opa-paths.js.map +1 -0
- package/dist/lib/regal-cli.d.ts +16 -1
- package/dist/lib/regal-cli.d.ts.map +1 -1
- package/dist/lib/regal-cli.js +40 -6
- package/dist/lib/regal-cli.js.map +1 -1
- package/dist/lib/rego-ast-walker.d.ts.map +1 -1
- package/dist/lib/rego-ast-walker.js +141 -17
- package/dist/lib/rego-ast-walker.js.map +1 -1
- package/dist/lib/rego-counterexample.d.ts +1 -1
- package/dist/lib/rego-counterexample.d.ts.map +1 -1
- package/dist/lib/rego-counterexample.js +23 -5
- package/dist/lib/rego-counterexample.js.map +1 -1
- package/dist/lib/rego-ir.d.ts +32 -2
- package/dist/lib/rego-ir.d.ts.map +1 -1
- package/dist/lib/rego-smt-encoder.d.ts +53 -5
- package/dist/lib/rego-smt-encoder.d.ts.map +1 -1
- package/dist/lib/rego-smt-encoder.js +192 -26
- package/dist/lib/rego-smt-encoder.js.map +1 -1
- package/dist/lib/rego-type-inferencer.d.ts +1 -1
- package/dist/lib/rego-type-inferencer.d.ts.map +1 -1
- package/dist/lib/rego-type-inferencer.js +3 -3
- package/dist/lib/rego-type-inferencer.js.map +1 -1
- package/dist/lib/rego-verify-engine.d.ts.map +1 -1
- package/dist/lib/rego-verify-engine.js +109 -77
- package/dist/lib/rego-verify-engine.js.map +1 -1
- package/dist/lib/rego-z3.d.ts +10 -0
- package/dist/lib/rego-z3.d.ts.map +1 -1
- package/dist/lib/rego-z3.js +38 -0
- package/dist/lib/rego-z3.js.map +1 -1
- package/dist/lib/security.d.ts +8 -0
- package/dist/lib/security.d.ts.map +1 -1
- package/dist/lib/security.js +130 -54
- package/dist/lib/security.js.map +1 -1
- package/dist/resources/patterns.d.ts +1 -1
- package/dist/resources/patterns.d.ts.map +1 -1
- package/dist/resources/patterns.js +40 -12
- package/dist/resources/patterns.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/bundles/build.d.ts.map +1 -1
- package/dist/tools/bundles/build.js +12 -4
- package/dist/tools/bundles/build.js.map +1 -1
- package/dist/tools/bundles/sign.d.ts +9 -2
- package/dist/tools/bundles/sign.d.ts.map +1 -1
- package/dist/tools/bundles/sign.js +145 -19
- package/dist/tools/bundles/sign.js.map +1 -1
- package/dist/tools/bundles/verify.d.ts +1 -1
- package/dist/tools/bundles/verify.d.ts.map +1 -1
- package/dist/tools/bundles/verify.js +58 -19
- package/dist/tools/bundles/verify.js.map +1 -1
- package/dist/tools/conftest/pull.d.ts.map +1 -1
- package/dist/tools/conftest/pull.js +24 -10
- package/dist/tools/conftest/pull.js.map +1 -1
- package/dist/tools/conftest/push.d.ts.map +1 -1
- package/dist/tools/conftest/push.js +17 -7
- package/dist/tools/conftest/push.js.map +1 -1
- package/dist/tools/conftest/test.d.ts +10 -6
- package/dist/tools/conftest/test.d.ts.map +1 -1
- package/dist/tools/conftest/test.js +47 -24
- package/dist/tools/conftest/test.js.map +1 -1
- package/dist/tools/conftest/verify.d.ts +10 -6
- package/dist/tools/conftest/verify.d.ts.map +1 -1
- package/dist/tools/conftest/verify.js +30 -18
- package/dist/tools/conftest/verify.js.map +1 -1
- package/dist/tools/evaluation/bench.d.ts +16 -0
- package/dist/tools/evaluation/bench.d.ts.map +1 -1
- package/dist/tools/evaluation/bench.js +30 -5
- package/dist/tools/evaluation/bench.js.map +1 -1
- package/dist/tools/evaluation/exec.d.ts +16 -0
- package/dist/tools/evaluation/exec.d.ts.map +1 -1
- package/dist/tools/evaluation/exec.js +35 -2
- package/dist/tools/evaluation/exec.js.map +1 -1
- package/dist/tools/evaluation/test-multiroot.d.ts +4 -0
- package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
- package/dist/tools/evaluation/test-multiroot.js +12 -2
- package/dist/tools/evaluation/test-multiroot.js.map +1 -1
- package/dist/tools/evaluation/test.d.ts +45 -0
- package/dist/tools/evaluation/test.d.ts.map +1 -1
- package/dist/tools/evaluation/test.js +146 -27
- package/dist/tools/evaluation/test.js.map +1 -1
- package/dist/tools/helpers/coverage-gaps.d.ts +11 -3
- package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -1
- package/dist/tools/helpers/coverage-gaps.js +4 -3
- package/dist/tools/helpers/coverage-gaps.js.map +1 -1
- package/dist/tools/helpers/explain-undefined.d.ts +9 -3
- package/dist/tools/helpers/explain-undefined.d.ts.map +1 -1
- package/dist/tools/helpers/explain-undefined.js +83 -51
- package/dist/tools/helpers/explain-undefined.js.map +1 -1
- package/dist/tools/helpers/verify.d.ts.map +1 -1
- package/dist/tools/helpers/verify.js +5 -1
- package/dist/tools/helpers/verify.js.map +1 -1
- package/dist/tools/server-management/_shared.d.ts +15 -4
- package/dist/tools/server-management/_shared.d.ts.map +1 -1
- package/dist/tools/server-management/_shared.js +73 -12
- package/dist/tools/server-management/_shared.js.map +1 -1
- package/dist/tools/server-management/data.d.ts.map +1 -1
- package/dist/tools/server-management/data.js +88 -23
- package/dist/tools/server-management/data.js.map +1 -1
- package/dist/tools/server-management/decisions.d.ts.map +1 -1
- package/dist/tools/server-management/decisions.js +16 -3
- package/dist/tools/server-management/decisions.js.map +1 -1
- package/dist/tools/server-management/policies.d.ts.map +1 -1
- package/dist/tools/server-management/policies.js +44 -7
- package/dist/tools/server-management/policies.js.map +1 -1
- package/dist/tools/server-management/status.d.ts.map +1 -1
- package/dist/tools/server-management/status.js +80 -13
- package/dist/tools/server-management/status.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,336 @@ 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
|
+
|
|
20
350
|
## [0.4.0] - 2026-09-03
|
|
21
351
|
|
|
22
352
|
### Security
|
|
@@ -29,9 +359,15 @@ not part of the public surface and may change in minor releases.
|
|
|
29
359
|
`rego_eval` accepts inline source, so `OPA_MCP_ALLOWED_PATHS` never applied and no
|
|
30
360
|
filesystem access was needed; a policy arriving through a README, an issue, or a
|
|
31
361
|
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
|
|
33
|
-
|
|
34
|
-
|
|
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`.
|
|
35
371
|
|
|
36
372
|
On Windows, libuv copies a fixed set of variables to every child regardless of what
|
|
37
373
|
is requested. `USERNAME`, `USERDOMAIN` and `LOGONSERVER` cannot be removed, so they
|