@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.
- package/CHANGELOG.md +244 -1
- package/README.md +98 -51
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +13 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -5
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +1 -6
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +17 -3
- package/dist/constants.js.map +1 -1
- package/dist/lib/conftest-cli.d.ts.map +1 -1
- package/dist/lib/conftest-cli.js +81 -17
- package/dist/lib/conftest-cli.js.map +1 -1
- package/dist/lib/errors.d.ts +4 -5
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +15 -3
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/inline-paths.d.ts +37 -0
- package/dist/lib/inline-paths.d.ts.map +1 -0
- package/dist/lib/inline-paths.js +162 -0
- package/dist/lib/inline-paths.js.map +1 -0
- package/dist/lib/opa-cli.d.ts +10 -0
- package/dist/lib/opa-cli.d.ts.map +1 -1
- package/dist/lib/opa-cli.js +9 -2
- package/dist/lib/opa-cli.js.map +1 -1
- package/dist/lib/opa-client.d.ts +27 -1
- package/dist/lib/opa-client.d.ts.map +1 -1
- package/dist/lib/opa-client.js +98 -14
- package/dist/lib/opa-client.js.map +1 -1
- package/dist/lib/opa-paths.d.ts +11 -1
- package/dist/lib/opa-paths.d.ts.map +1 -1
- package/dist/lib/opa-paths.js +25 -21
- package/dist/lib/opa-paths.js.map +1 -1
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +83 -10
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/rego-ast-walker.d.ts +0 -6
- package/dist/lib/rego-ast-walker.d.ts.map +1 -1
- package/dist/lib/rego-ast-walker.js +48 -46
- package/dist/lib/rego-ast-walker.js.map +1 -1
- package/dist/lib/rego-counterexample.d.ts +14 -1
- package/dist/lib/rego-counterexample.d.ts.map +1 -1
- package/dist/lib/rego-counterexample.js +40 -10
- package/dist/lib/rego-counterexample.js.map +1 -1
- package/dist/lib/rego-input-path.d.ts +20 -0
- package/dist/lib/rego-input-path.d.ts.map +1 -0
- package/dist/lib/rego-input-path.js +70 -0
- package/dist/lib/rego-input-path.js.map +1 -0
- package/dist/lib/rego-ir.d.ts +2 -1
- package/dist/lib/rego-ir.d.ts.map +1 -1
- package/dist/lib/rego-smt-encoder.d.ts +35 -0
- package/dist/lib/rego-smt-encoder.d.ts.map +1 -1
- package/dist/lib/rego-smt-encoder.js +81 -8
- package/dist/lib/rego-smt-encoder.js.map +1 -1
- package/dist/lib/rego-type-inferencer.d.ts +26 -1
- package/dist/lib/rego-type-inferencer.d.ts.map +1 -1
- package/dist/lib/rego-type-inferencer.js +68 -0
- 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 +171 -90
- package/dist/lib/rego-verify-engine.js.map +1 -1
- package/dist/lib/rego-z3.d.ts +56 -0
- package/dist/lib/rego-z3.d.ts.map +1 -1
- package/dist/lib/rego-z3.js +276 -7
- package/dist/lib/rego-z3.js.map +1 -1
- package/dist/lib/subprocess.d.ts +13 -0
- package/dist/lib/subprocess.d.ts.map +1 -1
- package/dist/lib/subprocess.js +153 -18
- package/dist/lib/subprocess.js.map +1 -1
- package/dist/lib/tool-helpers.d.ts +12 -25
- package/dist/lib/tool-helpers.d.ts.map +1 -1
- package/dist/lib/tool-helpers.js +66 -40
- package/dist/lib/tool-helpers.js.map +1 -1
- package/dist/prompts/index.js +2 -2
- package/dist/resources/index.js +1 -1
- package/dist/resources/index.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 +2 -3
- package/dist/resources/patterns.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +40 -5
- package/dist/server.js.map +1 -1
- package/dist/tools/authoring/capabilities.d.ts +4 -0
- package/dist/tools/authoring/capabilities.d.ts.map +1 -1
- package/dist/tools/authoring/capabilities.js +41 -4
- package/dist/tools/authoring/capabilities.js.map +1 -1
- package/dist/tools/authoring/check-schema.d.ts +6 -0
- package/dist/tools/authoring/check-schema.d.ts.map +1 -1
- package/dist/tools/authoring/check-schema.js +56 -3
- package/dist/tools/authoring/check-schema.js.map +1 -1
- package/dist/tools/authoring/format.d.ts.map +1 -1
- package/dist/tools/authoring/format.js +2 -2
- package/dist/tools/authoring/format.js.map +1 -1
- package/dist/tools/authoring/lint.d.ts.map +1 -1
- package/dist/tools/authoring/lint.js +8 -6
- package/dist/tools/authoring/lint.js.map +1 -1
- package/dist/tools/authoring/migrate-v1.d.ts.map +1 -1
- package/dist/tools/authoring/migrate-v1.js +20 -4
- package/dist/tools/authoring/migrate-v1.js.map +1 -1
- package/dist/tools/authoring/parse.d.ts.map +1 -1
- package/dist/tools/authoring/parse.js +3 -3
- package/dist/tools/authoring/parse.js.map +1 -1
- package/dist/tools/bundles/sign.d.ts.map +1 -1
- package/dist/tools/bundles/sign.js +14 -34
- package/dist/tools/bundles/sign.js.map +1 -1
- package/dist/tools/conftest/index.d.ts +5 -0
- package/dist/tools/conftest/index.d.ts.map +1 -1
- package/dist/tools/conftest/index.js.map +1 -1
- package/dist/tools/conftest/test.d.ts.map +1 -1
- package/dist/tools/conftest/test.js +16 -17
- package/dist/tools/conftest/test.js.map +1 -1
- package/dist/tools/conftest/verify.d.ts.map +1 -1
- package/dist/tools/conftest/verify.js +14 -18
- package/dist/tools/conftest/verify.js.map +1 -1
- package/dist/tools/evaluation/_shared.js +9 -12
- package/dist/tools/evaluation/_shared.js.map +1 -1
- package/dist/tools/evaluation/bench.d.ts +20 -9
- package/dist/tools/evaluation/bench.d.ts.map +1 -1
- package/dist/tools/evaluation/bench.js +31 -12
- package/dist/tools/evaluation/bench.js.map +1 -1
- package/dist/tools/evaluation/compile.js +4 -4
- package/dist/tools/evaluation/compile.js.map +1 -1
- package/dist/tools/evaluation/eval.d.ts.map +1 -1
- package/dist/tools/evaluation/eval.js +12 -16
- package/dist/tools/evaluation/eval.js.map +1 -1
- package/dist/tools/evaluation/exec.d.ts.map +1 -1
- package/dist/tools/evaluation/exec.js +3 -4
- package/dist/tools/evaluation/exec.js.map +1 -1
- package/dist/tools/evaluation/test-multiroot.d.ts +2 -0
- package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
- package/dist/tools/evaluation/test-multiroot.js +23 -6
- package/dist/tools/evaluation/test-multiroot.js.map +1 -1
- package/dist/tools/evaluation/test.d.ts.map +1 -1
- package/dist/tools/evaluation/test.js +8 -6
- package/dist/tools/evaluation/test.js.map +1 -1
- package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -1
- package/dist/tools/helpers/coverage-gaps.js +3 -4
- package/dist/tools/helpers/coverage-gaps.js.map +1 -1
- package/dist/tools/helpers/describe-policy.d.ts.map +1 -1
- package/dist/tools/helpers/describe-policy.js +2 -2
- package/dist/tools/helpers/describe-policy.js.map +1 -1
- package/dist/tools/helpers/explain-decision.d.ts.map +1 -1
- package/dist/tools/helpers/explain-decision.js +3 -4
- package/dist/tools/helpers/explain-decision.js.map +1 -1
- package/dist/tools/helpers/explain-undefined.d.ts.map +1 -1
- package/dist/tools/helpers/explain-undefined.js +131 -22
- package/dist/tools/helpers/explain-undefined.js.map +1 -1
- package/dist/tools/helpers/fix.d.ts +11 -5
- package/dist/tools/helpers/fix.d.ts.map +1 -1
- package/dist/tools/helpers/fix.js +88 -45
- package/dist/tools/helpers/fix.js.map +1 -1
- package/dist/tools/helpers/generate-test-skeleton.d.ts.map +1 -1
- package/dist/tools/helpers/generate-test-skeleton.js +105 -21
- package/dist/tools/helpers/generate-test-skeleton.js.map +1 -1
- package/dist/tools/helpers/playground-share.d.ts +4 -2
- package/dist/tools/helpers/playground-share.d.ts.map +1 -1
- package/dist/tools/helpers/playground-share.js +13 -3
- package/dist/tools/helpers/playground-share.js.map +1 -1
- package/dist/tools/helpers/policy-diff.d.ts.map +1 -1
- package/dist/tools/helpers/policy-diff.js +3 -4
- package/dist/tools/helpers/policy-diff.js.map +1 -1
- package/dist/tools/helpers/security-audit.d.ts.map +1 -1
- package/dist/tools/helpers/security-audit.js +19 -19
- package/dist/tools/helpers/security-audit.js.map +1 -1
- package/dist/tools/meta/index.d.ts +1 -1
- package/dist/tools/server-management/_shared.d.ts.map +1 -1
- package/dist/tools/server-management/_shared.js +13 -1
- package/dist/tools/server-management/_shared.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/lib/rego-z3.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Z3 singleton initialization.
|
|
3
3
|
*
|
|
4
|
-
* The z3-solver WASM module takes ~500ms to load and
|
|
5
|
-
*
|
|
6
|
-
* same promise. Each verification call
|
|
7
|
-
* from the shared Context
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/lib/rego-z3.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rego-z3.js","sourceRoot":"","sources":["../../src/lib/rego-z3.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rego-z3.js","sourceRoot":"","sources":["../../src/lib/rego-z3.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/subprocess.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/lib/subprocess.js
CHANGED
|
@@ -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
|
-
|
|
169
|
+
if (settled)
|
|
170
|
+
return;
|
|
171
|
+
signalTree(child, 'SIGTERM');
|
|
101
172
|
killTimer = setTimeout(() => {
|
|
102
|
-
if (
|
|
103
|
-
child
|
|
104
|
-
},
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (
|
|
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
|
-
|
|
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":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../src/lib/subprocess.ts"],"names":[],"mappings":"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"}
|