@orygn/opa-mcp 0.5.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 (176) hide show
  1. package/CHANGELOG.md +244 -1
  2. package/README.md +98 -51
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +1 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +13 -3
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +35 -5
  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/conftest-cli.d.ts.map +1 -1
  15. package/dist/lib/conftest-cli.js +81 -17
  16. package/dist/lib/conftest-cli.js.map +1 -1
  17. package/dist/lib/errors.d.ts +4 -5
  18. package/dist/lib/errors.d.ts.map +1 -1
  19. package/dist/lib/errors.js +15 -3
  20. package/dist/lib/errors.js.map +1 -1
  21. package/dist/lib/inline-paths.d.ts +37 -0
  22. package/dist/lib/inline-paths.d.ts.map +1 -0
  23. package/dist/lib/inline-paths.js +162 -0
  24. package/dist/lib/inline-paths.js.map +1 -0
  25. package/dist/lib/opa-cli.d.ts +10 -0
  26. package/dist/lib/opa-cli.d.ts.map +1 -1
  27. package/dist/lib/opa-cli.js +9 -2
  28. package/dist/lib/opa-cli.js.map +1 -1
  29. package/dist/lib/opa-client.d.ts +27 -1
  30. package/dist/lib/opa-client.d.ts.map +1 -1
  31. package/dist/lib/opa-client.js +98 -14
  32. package/dist/lib/opa-client.js.map +1 -1
  33. package/dist/lib/opa-paths.d.ts +11 -1
  34. package/dist/lib/opa-paths.d.ts.map +1 -1
  35. package/dist/lib/opa-paths.js +25 -21
  36. package/dist/lib/opa-paths.js.map +1 -1
  37. package/dist/lib/output.d.ts.map +1 -1
  38. package/dist/lib/output.js +83 -10
  39. package/dist/lib/output.js.map +1 -1
  40. package/dist/lib/rego-ast-walker.d.ts +0 -6
  41. package/dist/lib/rego-ast-walker.d.ts.map +1 -1
  42. package/dist/lib/rego-ast-walker.js +48 -46
  43. package/dist/lib/rego-ast-walker.js.map +1 -1
  44. package/dist/lib/rego-counterexample.d.ts +14 -1
  45. package/dist/lib/rego-counterexample.d.ts.map +1 -1
  46. package/dist/lib/rego-counterexample.js +40 -10
  47. package/dist/lib/rego-counterexample.js.map +1 -1
  48. package/dist/lib/rego-input-path.d.ts +20 -0
  49. package/dist/lib/rego-input-path.d.ts.map +1 -0
  50. package/dist/lib/rego-input-path.js +70 -0
  51. package/dist/lib/rego-input-path.js.map +1 -0
  52. package/dist/lib/rego-ir.d.ts +2 -1
  53. package/dist/lib/rego-ir.d.ts.map +1 -1
  54. package/dist/lib/rego-smt-encoder.d.ts +35 -0
  55. package/dist/lib/rego-smt-encoder.d.ts.map +1 -1
  56. package/dist/lib/rego-smt-encoder.js +81 -8
  57. package/dist/lib/rego-smt-encoder.js.map +1 -1
  58. package/dist/lib/rego-type-inferencer.d.ts +26 -1
  59. package/dist/lib/rego-type-inferencer.d.ts.map +1 -1
  60. package/dist/lib/rego-type-inferencer.js +68 -0
  61. package/dist/lib/rego-type-inferencer.js.map +1 -1
  62. package/dist/lib/rego-verify-engine.d.ts.map +1 -1
  63. package/dist/lib/rego-verify-engine.js +171 -90
  64. package/dist/lib/rego-verify-engine.js.map +1 -1
  65. package/dist/lib/rego-z3.d.ts +56 -0
  66. package/dist/lib/rego-z3.d.ts.map +1 -1
  67. package/dist/lib/rego-z3.js +276 -7
  68. package/dist/lib/rego-z3.js.map +1 -1
  69. package/dist/lib/subprocess.d.ts +13 -0
  70. package/dist/lib/subprocess.d.ts.map +1 -1
  71. package/dist/lib/subprocess.js +153 -18
  72. package/dist/lib/subprocess.js.map +1 -1
  73. package/dist/lib/tool-helpers.d.ts +12 -25
  74. package/dist/lib/tool-helpers.d.ts.map +1 -1
  75. package/dist/lib/tool-helpers.js +66 -40
  76. package/dist/lib/tool-helpers.js.map +1 -1
  77. package/dist/prompts/index.js +2 -2
  78. package/dist/resources/index.js +1 -1
  79. package/dist/resources/index.js.map +1 -1
  80. package/dist/resources/patterns.d.ts +1 -1
  81. package/dist/resources/patterns.d.ts.map +1 -1
  82. package/dist/resources/patterns.js +2 -3
  83. package/dist/resources/patterns.js.map +1 -1
  84. package/dist/server.d.ts +2 -2
  85. package/dist/server.d.ts.map +1 -1
  86. package/dist/server.js +40 -5
  87. package/dist/server.js.map +1 -1
  88. package/dist/tools/authoring/capabilities.d.ts +4 -0
  89. package/dist/tools/authoring/capabilities.d.ts.map +1 -1
  90. package/dist/tools/authoring/capabilities.js +41 -4
  91. package/dist/tools/authoring/capabilities.js.map +1 -1
  92. package/dist/tools/authoring/check-schema.d.ts +6 -0
  93. package/dist/tools/authoring/check-schema.d.ts.map +1 -1
  94. package/dist/tools/authoring/check-schema.js +56 -3
  95. package/dist/tools/authoring/check-schema.js.map +1 -1
  96. package/dist/tools/authoring/format.d.ts.map +1 -1
  97. package/dist/tools/authoring/format.js +2 -2
  98. package/dist/tools/authoring/format.js.map +1 -1
  99. package/dist/tools/authoring/lint.d.ts.map +1 -1
  100. package/dist/tools/authoring/lint.js +8 -6
  101. package/dist/tools/authoring/lint.js.map +1 -1
  102. package/dist/tools/authoring/migrate-v1.d.ts.map +1 -1
  103. package/dist/tools/authoring/migrate-v1.js +20 -4
  104. package/dist/tools/authoring/migrate-v1.js.map +1 -1
  105. package/dist/tools/authoring/parse.d.ts.map +1 -1
  106. package/dist/tools/authoring/parse.js +3 -3
  107. package/dist/tools/authoring/parse.js.map +1 -1
  108. package/dist/tools/bundles/sign.d.ts.map +1 -1
  109. package/dist/tools/bundles/sign.js +14 -34
  110. package/dist/tools/bundles/sign.js.map +1 -1
  111. package/dist/tools/conftest/index.d.ts +5 -0
  112. package/dist/tools/conftest/index.d.ts.map +1 -1
  113. package/dist/tools/conftest/index.js.map +1 -1
  114. package/dist/tools/conftest/test.d.ts.map +1 -1
  115. package/dist/tools/conftest/test.js +16 -17
  116. package/dist/tools/conftest/test.js.map +1 -1
  117. package/dist/tools/conftest/verify.d.ts.map +1 -1
  118. package/dist/tools/conftest/verify.js +14 -18
  119. package/dist/tools/conftest/verify.js.map +1 -1
  120. package/dist/tools/evaluation/_shared.js +9 -12
  121. package/dist/tools/evaluation/_shared.js.map +1 -1
  122. package/dist/tools/evaluation/bench.d.ts +20 -9
  123. package/dist/tools/evaluation/bench.d.ts.map +1 -1
  124. package/dist/tools/evaluation/bench.js +31 -12
  125. package/dist/tools/evaluation/bench.js.map +1 -1
  126. package/dist/tools/evaluation/compile.js +4 -4
  127. package/dist/tools/evaluation/compile.js.map +1 -1
  128. package/dist/tools/evaluation/eval.d.ts.map +1 -1
  129. package/dist/tools/evaluation/eval.js +12 -16
  130. package/dist/tools/evaluation/eval.js.map +1 -1
  131. package/dist/tools/evaluation/exec.d.ts.map +1 -1
  132. package/dist/tools/evaluation/exec.js +3 -4
  133. package/dist/tools/evaluation/exec.js.map +1 -1
  134. package/dist/tools/evaluation/test-multiroot.d.ts +2 -0
  135. package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
  136. package/dist/tools/evaluation/test-multiroot.js +23 -6
  137. package/dist/tools/evaluation/test-multiroot.js.map +1 -1
  138. package/dist/tools/evaluation/test.d.ts.map +1 -1
  139. package/dist/tools/evaluation/test.js +8 -6
  140. package/dist/tools/evaluation/test.js.map +1 -1
  141. package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -1
  142. package/dist/tools/helpers/coverage-gaps.js +3 -4
  143. package/dist/tools/helpers/coverage-gaps.js.map +1 -1
  144. package/dist/tools/helpers/describe-policy.d.ts.map +1 -1
  145. package/dist/tools/helpers/describe-policy.js +2 -2
  146. package/dist/tools/helpers/describe-policy.js.map +1 -1
  147. package/dist/tools/helpers/explain-decision.d.ts.map +1 -1
  148. package/dist/tools/helpers/explain-decision.js +3 -4
  149. package/dist/tools/helpers/explain-decision.js.map +1 -1
  150. package/dist/tools/helpers/explain-undefined.d.ts.map +1 -1
  151. package/dist/tools/helpers/explain-undefined.js +131 -22
  152. package/dist/tools/helpers/explain-undefined.js.map +1 -1
  153. package/dist/tools/helpers/fix.d.ts +11 -5
  154. package/dist/tools/helpers/fix.d.ts.map +1 -1
  155. package/dist/tools/helpers/fix.js +88 -45
  156. package/dist/tools/helpers/fix.js.map +1 -1
  157. package/dist/tools/helpers/generate-test-skeleton.d.ts.map +1 -1
  158. package/dist/tools/helpers/generate-test-skeleton.js +105 -21
  159. package/dist/tools/helpers/generate-test-skeleton.js.map +1 -1
  160. package/dist/tools/helpers/playground-share.d.ts +4 -2
  161. package/dist/tools/helpers/playground-share.d.ts.map +1 -1
  162. package/dist/tools/helpers/playground-share.js +13 -3
  163. package/dist/tools/helpers/playground-share.js.map +1 -1
  164. package/dist/tools/helpers/policy-diff.d.ts.map +1 -1
  165. package/dist/tools/helpers/policy-diff.js +3 -4
  166. package/dist/tools/helpers/policy-diff.js.map +1 -1
  167. package/dist/tools/helpers/security-audit.d.ts.map +1 -1
  168. package/dist/tools/helpers/security-audit.js +19 -19
  169. package/dist/tools/helpers/security-audit.js.map +1 -1
  170. package/dist/tools/meta/index.d.ts +1 -1
  171. package/dist/tools/server-management/_shared.d.ts.map +1 -1
  172. package/dist/tools/server-management/_shared.js +13 -1
  173. package/dist/tools/server-management/_shared.js.map +1 -1
  174. package/dist/types.d.ts +1 -1
  175. package/dist/types.d.ts.map +1 -1
  176. package/package.json +1 -1
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Z3 singleton initialization.
3
3
  *
4
- * The z3-solver WASM module takes ~500ms to load and must only be
5
- * initialized once per process. Concurrent calls safely await the
6
- * same promise. Each verification call creates its own fresh Solver
7
- * from the shared Context, so contexts never accumulate stale state.
4
+ * The z3-solver WASM module takes ~500ms to load and is initialized once,
5
+ * unless it faults, in which case a fresh one replaces it (see getZ3).
6
+ * Concurrent calls safely await the same promise. Each verification call
7
+ * creates its own fresh Solver from the shared Context and releases it, and
8
+ * its model, as it finishes; that is what keeps the heap bounded.
8
9
  *
9
10
  * A fresh Solver is NOT enough to make concurrent verification safe. The whole
10
11
  * Context lives in one single-threaded WASM heap, and `check()` is async, so two
@@ -13,19 +14,264 @@
13
14
  * inside the WASM module. Everything touching the Context must therefore run
14
15
  * under `withZ3Lock`.
15
16
  */
17
+ import { AsyncLocalStorage } from 'node:async_hooks';
16
18
  import { init } from 'z3-solver';
19
+ /**
20
+ * Ceiling on Z3's own allocations, in megabytes. Reached, Z3 raises an
21
+ * ordinary exception that the engine turns into an inconclusive verdict.
22
+ * Without it the WASM heap itself runs out, and that abort surfaces outside
23
+ * every try/catch as an uncaughtException that ends the server.
24
+ */
25
+ export const Z3_MEMORY_MAX_MB = 1024;
26
+ /**
27
+ * The solver's own bound, checked at its checkpoints, where running out
28
+ * degrades to an "unknown" answer. It sits well below the process ceiling on
29
+ * purpose: at the same value the allocator's exception won the race, and an
30
+ * allocation failing inside a destructor ends in an abort rather than an
31
+ * error. Measured in review: equal caps aborted four times in four; a lower
32
+ * solver bound answered "unknown" four times in four.
33
+ */
34
+ export const Z3_SOLVER_MAX_MEMORY_MB = 768;
17
35
  // Module-level singleton
18
36
  let z3InitPromise = null;
37
+ let z3Api;
38
+ /** Set once Z3 has failed outside a try/catch; it is not trusted again. */
39
+ let z3Unusable;
40
+ /** Number of Z3 critical sections currently running (0 or 1). */
41
+ let z3Depth = 0;
42
+ /** Rejects the section in flight; set while one is running. */
43
+ let poisonInFlight;
44
+ /** Generation of the module in use; a finalizer from an earlier one is dropped. */
45
+ let z3Generation = 0;
46
+ /** Finalizers that arrived while a solve was running, to run once it is not. */
47
+ let deferredFinalizers = [];
48
+ /** Fresh modules this process may still bring up after a fault. */
49
+ let recoveriesLeft = 3;
50
+ /**
51
+ * The registry class this process started with, and the identity of each
52
+ * init along its own async chain: z3-solver builds its registry in the
53
+ * continuation after its WASM loads, so the store there names the init that
54
+ * owns it, however inits interleave.
55
+ */
56
+ const NativeRegistry = globalThis.FinalizationRegistry;
57
+ const registryGlobal = globalThis;
58
+ const initInFlight = new AsyncLocalStorage();
59
+ /**
60
+ * Inits whose window is open; the global goes back when the last closes. An
61
+ * init that never settles leaves it on the subclass, which behaves natively
62
+ * for everything off an init's chain: only the class identity differs.
63
+ */
64
+ let initWindows = 0;
65
+ /**
66
+ * The stack at the call, with enough frames kept to reach the caller's module
67
+ * whatever `Error.stackTraceLimit` the host has chosen: a limit of zero, a
68
+ * common speed setting, would otherwise leave nothing to read and the wrap
69
+ * would quietly not happen.
70
+ */
71
+ function stackHere() {
72
+ const limit = Error.stackTraceLimit;
73
+ Error.stackTraceLimit = 20;
74
+ try {
75
+ return new Error().stack ?? '';
76
+ }
77
+ finally {
78
+ Error.stackTraceLimit = limit;
79
+ }
80
+ }
81
+ /**
82
+ * The registry z3-solver gets while an init runs.
83
+ *
84
+ * z3-solver frees every AST, solver and model from one FinalizationRegistry,
85
+ * built inside its createApi, whose callbacks run on the main thread whenever
86
+ * the collector gets to them. A solve runs on a worker over the same shared
87
+ * memory, and a callback landing mid-solve raced it on Z3's allocator and
88
+ * faulted the heap (measured: a collection forced mid-solve crashed inside a
89
+ * hundred solves; the same collection while the worker was idle ran 1500
90
+ * clean). So a finalizer that arrives while a section is open waits for the
91
+ * section to close, and one from a module that has since faulted is dropped.
92
+ *
93
+ * Each construction looks at its own stack and async context: one from
94
+ * z3-solver on an init's chain is wrapped with that init's generation; any
95
+ * other gets the real behaviour. Inits can overlap, since a recovery starts
96
+ * the next while the one given up on is still coming up, and each still
97
+ * gets its own generation: the frees of the abandoned module are dropped
98
+ * and the recovered module's are routed.
99
+ *
100
+ * Releasing the solver and model as each solve ends removes most of the
101
+ * finalizer traffic that made the race reachable; the deferral covers what
102
+ * a collection still frees.
103
+ */
104
+ class DeferringRegistry extends NativeRegistry {
105
+ constructor(callback) {
106
+ const owner = initInFlight.getStore();
107
+ const mine = owner !== undefined && stackHere().includes('z3-solver') ? owner : undefined;
108
+ const generation = mine?.generation;
109
+ super(mine === undefined
110
+ ? callback
111
+ : (held) => {
112
+ if (generation !== z3Generation)
113
+ return;
114
+ if (z3Depth > 0)
115
+ deferredFinalizers.push(() => callback(held));
116
+ else
117
+ callback(held);
118
+ });
119
+ }
120
+ }
121
+ /** Bring up z3-solver with its finalizers routed through this module. */
122
+ async function initModule() {
123
+ initWindows++;
124
+ registryGlobal.FinalizationRegistry = DeferringRegistry;
125
+ try {
126
+ return await initInFlight.run({ generation: z3Generation }, () => init());
127
+ }
128
+ finally {
129
+ if (--initWindows === 0)
130
+ registryGlobal.FinalizationRegistry = NativeRegistry;
131
+ }
132
+ }
133
+ /**
134
+ * Run the finalizers held back during a solve; only called with the worker
135
+ * idle. Each is a dec_ref; one that throws must not take the rest, or the
136
+ * lock, with it.
137
+ */
138
+ function runDeferredFinalizers() {
139
+ const run = deferredFinalizers;
140
+ deferredFinalizers = [];
141
+ for (const finalizer of run) {
142
+ try {
143
+ finalizer();
144
+ }
145
+ catch {
146
+ // A free that fails leaks one object; the section still closes.
147
+ }
148
+ }
149
+ }
19
150
  /**
20
151
  * Return the shared Z3 Context, initializing WASM on first call.
21
152
  * Safe to call from concurrent async paths.
22
153
  */
23
154
  export async function getZ3() {
155
+ if (z3Unusable !== undefined) {
156
+ if (recoveriesLeft === 0) {
157
+ throw new Error(`Z3 is unavailable in this process after repeated failures (${z3Unusable}). Restart the server to verify again.`);
158
+ }
159
+ // The heap that faulted cannot be trusted, so bring up a fresh module.
160
+ // Every init() is a new WASM instance with its own memory and worker
161
+ // (measured: two live side by side, independent, ~100 ms each), so
162
+ // nothing is shared with the one that faulted; its finalizers were
163
+ // dropped by generation when it was given up on. The faulted instance
164
+ // is retained, about 30 MB and one worker each, which is why the number
165
+ // of recoveries is bounded for the life of the process.
166
+ recoveriesLeft--;
167
+ z3Unusable = undefined;
168
+ z3InitPromise = null;
169
+ z3Api = undefined;
170
+ }
24
171
  if (z3InitPromise === null) {
25
- z3InitPromise = init().then(({ Context }) => Context('main'));
172
+ const started = initModule().then((api) => {
173
+ // An init a recovery superseded while it was coming up must not
174
+ // become the module in use; whoever was waiting on it is told.
175
+ if (z3InitPromise !== started)
176
+ throw new Error('Z3 init superseded by a recovery');
177
+ api.setParam('memory_max_size', Z3_MEMORY_MAX_MB);
178
+ z3Api = api;
179
+ return api.Context('main');
180
+ });
181
+ z3InitPromise = started;
26
182
  }
27
183
  return z3InitPromise;
28
184
  }
185
+ /** Read back a Z3 global parameter, after initialisation. */
186
+ export async function getZ3Param(name) {
187
+ await getZ3();
188
+ return z3Api?.getParam(name) ?? null;
189
+ }
190
+ /** Whether a Z3 critical section is running right now. */
191
+ export function isZ3Busy() {
192
+ return z3Depth > 0;
193
+ }
194
+ /**
195
+ * Give up on the Z3 module in use. Called when it failed outside a try/catch:
196
+ * the heap it lives in cannot be trusted. The next call brings up a fresh
197
+ * module, a bounded number of times per process.
198
+ */
199
+ export function markZ3Unusable(reason) {
200
+ z3Unusable = reason;
201
+ // Move the generation now, before anything unwinds: the poison below ends
202
+ // the section, whose close would otherwise run every deferred free into
203
+ // the heap that just faulted, and any finalizer that arrives later from
204
+ // this module must be dropped rather than run.
205
+ z3Generation++;
206
+ deferredFinalizers = [];
207
+ // A heap abort arrives from the WASM worker and leaves the solve's promise
208
+ // unsettled for good. Settle it here, so the section releases the lock and
209
+ // the calls queued behind it are answered instead of hanging.
210
+ poisonInFlight?.(new Error(`Z3 became unusable during the solve (${reason}).`));
211
+ }
212
+ /**
213
+ * Whether an error message is one of the two this module produces once Z3
214
+ * has been given up on. The engine passes such a message through to the
215
+ * caller verbatim, since a restart is the one thing they can do about it.
216
+ */
217
+ export function isZ3UnavailableMessage(detail) {
218
+ return /Z3 (is unavailable|became unusable)/.test(detail);
219
+ }
220
+ /**
221
+ * Whether a failure is the solve in flight being cut short by a fault, which
222
+ * a fresh module can answer: the engine retries such a call once.
223
+ */
224
+ export function isZ3RecoverableMessage(detail) {
225
+ return /Z3 became unusable during the solve/.test(detail);
226
+ }
227
+ /**
228
+ * How many fresh modules this process may still bring up after a fault.
229
+ * Three for the life of the process, however far apart the faults: each
230
+ * retained instance costs memory, and a fourth fault is a pattern to
231
+ * restart out of, not to ride.
232
+ */
233
+ export function z3RecoveriesLeft() {
234
+ return recoveriesLeft;
235
+ }
236
+ /** For tests: how many finalizers are waiting for the open section to close. */
237
+ export function deferredFinalizersForTesting() {
238
+ return deferredFinalizers.length;
239
+ }
240
+ /**
241
+ * For tests: what z3-solver's finalizers go through. Runs at once when no
242
+ * section is open, otherwise once the open one closes.
243
+ */
244
+ export function enqueueFinalizerForTesting(finalizer) {
245
+ if (z3Depth > 0)
246
+ deferredFinalizers.push(finalizer);
247
+ else
248
+ finalizer();
249
+ }
250
+ /**
251
+ * Whether an uncaught error is the WASM heap giving out, rather than some
252
+ * unrelated failure that happened while a solve was running.
253
+ */
254
+ export function isZ3Failure(e) {
255
+ // A WebAssembly.RuntimeError is named just that; the global is not in this
256
+ // project's compiler libs, so the name is the check.
257
+ if (e instanceof Error && e.name === 'RuntimeError')
258
+ return true;
259
+ const message = e instanceof Error ? e.message : String(e);
260
+ // A call-stack overflow was also seen once as a symptom of a corrupted
261
+ // heap; it counts only when the stack shows it came from the WASM glue,
262
+ // so an overflow elsewhere does not spend a recovery. With no frames to
263
+ // read (a host that keeps none) the conservative answer stands: while a
264
+ // solve is running, the overflow is Z3's.
265
+ if (/Maximum call stack size exceeded/.test(message)) {
266
+ if (!(e instanceof Error))
267
+ return false;
268
+ const stack = e.stack ?? '';
269
+ if (!/\n\s+at /.test(stack))
270
+ return true;
271
+ return stack.includes('z3-built');
272
+ }
273
+ return /Aborted\(|memory access out of bounds|out of memory|unreachable executed/i.test(message);
274
+ }
29
275
  /**
30
276
  * Tail of the queue of pending Z3 critical sections. Each acquirer waits on the
31
277
  * current tail and installs its own completion as the new tail, so sections run
@@ -49,11 +295,27 @@ export async function withZ3Lock(fn) {
49
295
  const predecessor = z3LockTail;
50
296
  z3LockTail = predecessor.then(() => mine);
51
297
  await predecessor;
298
+ z3Depth++;
299
+ const poisoned = new Promise((_resolve, reject) => {
300
+ poisonInFlight = reject;
301
+ });
52
302
  try {
53
- return await fn();
303
+ return await Promise.race([fn(), poisoned]);
54
304
  }
55
305
  finally {
56
- release();
306
+ poisonInFlight = undefined;
307
+ z3Depth--;
308
+ try {
309
+ // The worker is idle: whatever the collector noticed mid-solve can be
310
+ // freed now.
311
+ if (z3Depth === 0)
312
+ runDeferredFinalizers();
313
+ }
314
+ finally {
315
+ // Whatever happened above, the lock must pass on, or every later call
316
+ // waits for ever.
317
+ release();
318
+ }
57
319
  }
58
320
  }
59
321
  /**
@@ -62,6 +324,13 @@ export async function withZ3Lock(fn) {
62
324
  */
63
325
  export function resetZ3ForTesting() {
64
326
  z3InitPromise = null;
327
+ z3Api = undefined;
328
+ z3Unusable = undefined;
329
+ z3Depth = 0;
330
+ poisonInFlight = undefined;
65
331
  z3LockTail = Promise.resolve();
332
+ z3Generation++;
333
+ deferredFinalizers = [];
334
+ recoveriesLeft = 3;
66
335
  }
67
336
  //# sourceMappingURL=rego-z3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rego-z3.js","sourceRoot":"","sources":["../../src/lib/rego-z3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,yBAAyB;AACzB,IAAI,aAAa,GAA4B,IAAI,CAAC;AAElD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,aAAa,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,aAAmC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,IAAI,UAAU,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAI,EAAoB;IACtD,IAAI,OAAoB,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACzC,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,UAAU,CAAC;IAC/B,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,WAAW,CAAC;IAClB,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,IAAI,CAAC;IACrB,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"rego-z3.js","sourceRoot":"","sources":["../../src/lib/rego-z3.ts"],"names":[],"mappings":"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"}
@@ -54,7 +54,20 @@ export interface SpawnResult {
54
54
  * valid; absent means "not truncated".
55
55
  */
56
56
  outputTruncated?: boolean;
57
+ /**
58
+ * The signal that ended the child, when one did. Set for the server's own
59
+ * kills (timeout, cancellation, output cap) and for kills from outside it,
60
+ * such as the kernel's out-of-memory killer. Optional for the same reason as
61
+ * `outputTruncated`.
62
+ */
63
+ signal?: NodeJS.Signals | null;
57
64
  }
65
+ /**
66
+ * Signal every child still running. A child sits in its own process group on
67
+ * POSIX, so a signal that stops the server does not reach it on its own; the
68
+ * server calls this on the way out. Returns how many were signalled.
69
+ */
70
+ export declare function terminateChildren(sig?: NodeJS.Signals): number;
58
71
  /**
59
72
  * Run a binary and return its captured output. Never throws -- failures are
60
73
  * reflected in `exitCode` / `timedOut` / `outputTruncated`.
@@ -1 +1 @@
1
- {"version":3,"file":"subprocess.d.ts","sourceRoot":"","sources":["../../src/lib/subprocess.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,wDAAwD;IACxD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA6CD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAmIxF"}
1
+ {"version":3,"file":"subprocess.d.ts","sourceRoot":"","sources":["../../src/lib/subprocess.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,wDAAwD;IACxD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;CAChC;AAgDD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,OAAmB,GAAG,MAAM,CAOzE;AA6CD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA4MxF"}
@@ -25,6 +25,61 @@ import { buildChildEnv } from './child-env.js';
25
25
  * OPA_MCP_MAX_SUBPROCESS_BYTES.
26
26
  */
27
27
  export const DEFAULT_MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
28
+ /**
29
+ * How long to wait for the stdio pipes to close once the child has exited.
30
+ *
31
+ * The child's own output is complete at 'exit'; 'close' follows when every
32
+ * holder of the pipes is gone. A grandchild that inherited them, which is the
33
+ * ordinary shape of a wrapper script around the binary, keeps 'close' from
34
+ * ever firing, and a result that waits for it never settles.
35
+ */
36
+ const PIPE_DRAIN_GRACE_MS = 1_000;
37
+ /** Grace between SIGTERM and SIGKILL. */
38
+ const KILL_ESCALATION_MS = 2_000;
39
+ /**
40
+ * Ceiling on the drain after 'exit', however often late data re-arms it. The
41
+ * deadline bounds the drain while it is still pending; once it has fired, a
42
+ * writer that survived the group signal could otherwise keep the result open
43
+ * for as long as it kept writing.
44
+ */
45
+ const PIPE_DRAIN_MAX_MS = 5 * PIPE_DRAIN_GRACE_MS;
46
+ /**
47
+ * Signal the child, and on POSIX its whole process group, so a grandchild
48
+ * started by a wrapper script dies with it. The child is spawned as a group
49
+ * leader for this purpose; when the group is already gone, or the platform
50
+ * has no groups, fall back to the child alone.
51
+ */
52
+ function signalTree(child, sig) {
53
+ // The group is addressed by the child's pid, which the kernel may hand to
54
+ // an unrelated process once the child has been reaped. Past that point only
55
+ // the handle is safe to use, and Node's kill on a dead handle is a no-op.
56
+ const unreaped = child.exitCode === null && child.signalCode === null;
57
+ if (unreaped && process.platform !== 'win32' && child.pid !== undefined) {
58
+ try {
59
+ process.kill(-child.pid, sig);
60
+ return;
61
+ }
62
+ catch {
63
+ // ESRCH or EPERM: no group to signal. The child itself may still be there.
64
+ }
65
+ }
66
+ child.kill(sig);
67
+ }
68
+ /** Children that have been spawned and have not settled yet. */
69
+ const liveChildren = new Set();
70
+ /**
71
+ * Signal every child still running. A child sits in its own process group on
72
+ * POSIX, so a signal that stops the server does not reach it on its own; the
73
+ * server calls this on the way out. Returns how many were signalled.
74
+ */
75
+ export function terminateChildren(sig = 'SIGTERM') {
76
+ let n = 0;
77
+ for (const child of liveChildren) {
78
+ signalTree(child, sig);
79
+ n++;
80
+ }
81
+ return n;
82
+ }
28
83
  /** Accumulates a stream's chunks up to a byte ceiling. */
29
84
  class CappedBuffer {
30
85
  limit;
@@ -88,6 +143,9 @@ export async function runBinary(binary, opts) {
88
143
  env: buildChildEnv(opts.env),
89
144
  shell: false,
90
145
  windowsHide: true,
146
+ // A process group of its own on POSIX, so a kill reaches a grandchild
147
+ // as well. See signalTree.
148
+ detached: process.platform !== 'win32',
91
149
  });
92
150
  const limit = opts.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
93
151
  const stdout = new CappedBuffer(limit);
@@ -96,27 +154,53 @@ export async function runBinary(binary, opts) {
96
154
  let aborted = false;
97
155
  let settled = false;
98
156
  let killTimer;
157
+ let drainTimer;
158
+ /** Set once 'exit' has fired: the child is gone, only its pipes remain. */
159
+ let exited;
160
+ /** Absolute time by which the drain finishes regardless of late data. */
161
+ let drainUntil = 0;
162
+ liveChildren.add(child);
163
+ // Whether the child has actually ended. `child.killed` is not that: Node
164
+ // sets it as soon as a signal was sent, whether or not the child obeyed,
165
+ // so a guard on it never escalated and a child that trapped SIGTERM hung
166
+ // the call for good.
167
+ const alive = () => child.exitCode === null && child.signalCode === null;
99
168
  const killChild = () => {
100
- child.kill('SIGTERM');
169
+ if (settled)
170
+ return;
171
+ signalTree(child, 'SIGTERM');
101
172
  killTimer = setTimeout(() => {
102
- if (!child.killed)
103
- child.kill('SIGKILL');
104
- }, 2_000);
173
+ if (alive())
174
+ signalTree(child, 'SIGKILL');
175
+ }, KILL_ESCALATION_MS);
105
176
  };
106
177
  const timer = setTimeout(() => {
178
+ // The child is already gone and only the drain is pending: settle from
179
+ // what was captured. Calling that a timeout would be wrong.
180
+ if (exited) {
181
+ finishFromCapture();
182
+ return;
183
+ }
107
184
  timedOut = true;
108
185
  killChild();
109
186
  }, opts.timeoutMs);
110
- if (opts.signal) {
111
- opts.signal.addEventListener('abort', () => {
112
- aborted = true;
113
- killChild();
114
- }, { once: true });
115
- }
187
+ // Once the child has exited there is nothing to cancel, and a listener
188
+ // left behind after settling would signal a pid the kernel may have
189
+ // handed to someone else. rego_test_multiroot passes one signal through
190
+ // a whole sequence of runs, so the listener has to go when the run does.
191
+ const onAbort = () => {
192
+ if (settled || exited)
193
+ return;
194
+ aborted = true;
195
+ killChild();
196
+ };
197
+ opts.signal?.addEventListener('abort', onAbort, { once: true });
116
198
  const clearTimers = () => {
117
199
  clearTimeout(timer);
118
200
  if (killTimer)
119
201
  clearTimeout(killTimer);
202
+ if (drainTimer)
203
+ clearTimeout(drainTimer);
120
204
  };
121
205
  /**
122
206
  * Resolve at most once. 'error' and 'close' can both fire -- killing a child
@@ -128,16 +212,51 @@ export async function runBinary(binary, opts) {
128
212
  return;
129
213
  settled = true;
130
214
  clearTimers();
215
+ liveChildren.delete(child);
216
+ opts.signal?.removeEventListener('abort', onAbort);
131
217
  resolvePromise(result);
132
218
  };
133
- child.stdout?.on('data', (chunk) => {
134
- if (stdout.push(chunk))
135
- killChild();
136
- });
137
- child.stderr?.on('data', (chunk) => {
138
- if (stderr.push(chunk))
219
+ /**
220
+ * Build the result from the capture and let go of the pipes. Used once the
221
+ * child has exited but something it left behind still holds its stdio.
222
+ */
223
+ const finishFromCapture = () => {
224
+ if (settled || !exited)
225
+ return;
226
+ child.stdout?.destroy();
227
+ child.stderr?.destroy();
228
+ finish(exited.code, exited.signal);
229
+ };
230
+ // (Re)start the wait for 'close'. Bytes can still be sitting in the pipe
231
+ // at 'exit', and on a loaded machine the reads that deliver them may
232
+ // queue behind an expired timer; each chunk that arrives pushes the
233
+ // grace out again, and the deadline above bounds the whole thing.
234
+ const armDrain = () => {
235
+ if (drainTimer)
236
+ clearTimeout(drainTimer);
237
+ const left = drainUntil - Date.now();
238
+ if (left <= 0) {
239
+ finishFromCapture();
240
+ return;
241
+ }
242
+ drainTimer = setTimeout(finishFromCapture, Math.min(PIPE_DRAIN_GRACE_MS, left));
243
+ };
244
+ const onData = (buf, chunk) => {
245
+ const overflowed = buf.push(chunk);
246
+ if (exited) {
247
+ // Nothing left to kill; a writer that outlived the child is either
248
+ // done, or has just been cut off by the cap.
249
+ if (overflowed)
250
+ finishFromCapture();
251
+ else
252
+ armDrain();
253
+ return;
254
+ }
255
+ if (overflowed)
139
256
  killChild();
140
- });
257
+ };
258
+ child.stdout?.on('data', (chunk) => onData(stdout, chunk));
259
+ child.stderr?.on('data', (chunk) => onData(stderr, chunk));
141
260
  // Killing a child mid-write can surface an EPIPE on the pipe. Without a
142
261
  // listener that is an unhandled 'error' event, which would take the whole
143
262
  // server down -- the exact failure mode this cap exists to prevent.
@@ -153,9 +272,10 @@ export async function runBinary(binary, opts) {
153
272
  aborted,
154
273
  durationMs: Date.now() - start,
155
274
  outputTruncated: false,
275
+ signal: null,
156
276
  });
157
277
  });
158
- child.on('close', (code) => {
278
+ const finish = (code, signal) => {
159
279
  // Decoding runs here, in an async callback whose throw would escape every
160
280
  // try/catch upstream and reach the process as an uncaughtException. The
161
281
  // byte cap is what makes that unreachable; this is the belt to its braces.
@@ -168,6 +288,7 @@ export async function runBinary(binary, opts) {
168
288
  aborted,
169
289
  durationMs: Date.now() - start,
170
290
  outputTruncated: stdout.didOverflow || stderr.didOverflow,
291
+ signal,
171
292
  });
172
293
  }
173
294
  catch (e) {
@@ -179,9 +300,23 @@ export async function runBinary(binary, opts) {
179
300
  aborted,
180
301
  durationMs: Date.now() - start,
181
302
  outputTruncated: true,
303
+ signal,
182
304
  });
183
305
  }
306
+ };
307
+ // 'close' carries the complete output and is the normal way to finish.
308
+ // 'exit' starts a short grace for it: when the pipes are still held open
309
+ // by something the child left behind, the result is built from what was
310
+ // captured and the server's ends of the pipes are released.
311
+ child.on('exit', (code, signal) => {
312
+ // A spawn failure settles on 'error' and may still be followed by 'exit'.
313
+ if (settled)
314
+ return;
315
+ exited = { code, signal };
316
+ drainUntil = Date.now() + PIPE_DRAIN_MAX_MS;
317
+ armDrain();
184
318
  });
319
+ child.on('close', (code, signal) => finish(code, signal));
185
320
  if (opts.stdin !== undefined) {
186
321
  child.stdin?.write(opts.stdin);
187
322
  child.stdin?.end();
@@ -1 +1 @@
1
- {"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../src/lib/subprocess.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../src/lib/subprocess.ts"],"names":[],"mappings":"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"}