@rulvar/planner 1.38.0 → 1.40.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.
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ScriptRejected } from "@rulvar/core";
|
|
2
|
+
import * as acorn from "acorn";
|
|
3
|
+
import { scanDialect } from "eslint-plugin-rulvar";
|
|
2
4
|
//#region src/compile.ts
|
|
3
5
|
/**
|
|
4
6
|
* The exact curated sandbox global set, in canonical order.
|
|
@@ -164,41 +166,62 @@ function scanImports(source, blanked, allowImports) {
|
|
|
164
166
|
}
|
|
165
167
|
return diagnostics;
|
|
166
168
|
}
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
+
const CODEGEN_DIAGNOSTIC = {
|
|
170
|
+
eval: {
|
|
171
|
+
ruleId: "no-eval",
|
|
172
|
+
message: "eval is not part of the sandbox dialect; dynamically generated code reopens the import allowlist and the ambient capability surface the dialect closes"
|
|
173
|
+
},
|
|
174
|
+
"function-constructor": {
|
|
175
|
+
ruleId: "no-function-constructor",
|
|
176
|
+
message: "the Function constructor is not part of the sandbox dialect; it compiles arbitrary code that bypasses the import allowlist (use only the curated globals)"
|
|
177
|
+
},
|
|
178
|
+
"constructor-access": {
|
|
179
|
+
ruleId: "no-constructor-access",
|
|
180
|
+
message: "constructor access is not part of the sandbox dialect; it reaches the Function constructor from any function value and reopens dynamic code generation"
|
|
181
|
+
}
|
|
182
|
+
};
|
|
169
183
|
/**
|
|
170
184
|
* Rejects dynamic code generation. `eval` and the Function constructor
|
|
171
185
|
* compile attacker supplied text in a fresh scope where the import
|
|
172
186
|
* expression, ambient time, and host capability are back in reach, so
|
|
173
187
|
* banning `import` while allowing `new Function("return import(x)")` closes
|
|
174
|
-
* nothing.
|
|
175
|
-
* function value exposes the Function constructor
|
|
176
|
-
* ((function(){}).constructor === Function)
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
188
|
+
* nothing. Constructor reconstruction is the same vector by another name:
|
|
189
|
+
* every function value exposes the Function constructor through its prototype
|
|
190
|
+
* ((function(){}).constructor === Function), reachable as `.constructor`,
|
|
191
|
+
* `["constructor"]`, a computed key that folds to the constant, a
|
|
192
|
+
* `{ constructor: x }` destructuring, or `Reflect.get(fn, "constructor")`.
|
|
193
|
+
*
|
|
194
|
+
* The scan runs the SAME shared AST policy the `no-code-generation` ESLint
|
|
195
|
+
* rule uses (`scanDialect`), so the linter and this structural gate reach one
|
|
196
|
+
* decision for every statically visible form. A truly dynamic key
|
|
197
|
+
* (`fn[valueFromAnAgent]`) cannot be resolved statically without rejecting
|
|
198
|
+
* every dynamic property access, so it is left to the worker realm, which
|
|
199
|
+
* neutralizes the runtime reconstruction path. A syntax error is reported by
|
|
200
|
+
* the AsyncFunction construction below, so a parse failure here yields no
|
|
201
|
+
* diagnostics rather than a duplicate.
|
|
180
202
|
*/
|
|
181
|
-
function scanCodegen(source
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
else diagnostics.push({
|
|
191
|
-
ruleId: "no-function-constructor",
|
|
192
|
-
message: "the Function constructor is not part of the sandbox dialect; it compiles arbitrary code that bypasses the import allowlist (use only the curated globals)",
|
|
193
|
-
...at
|
|
203
|
+
function scanCodegen(source) {
|
|
204
|
+
let program;
|
|
205
|
+
try {
|
|
206
|
+
program = acorn.parse(source, {
|
|
207
|
+
ecmaVersion: "latest",
|
|
208
|
+
sourceType: "module",
|
|
209
|
+
allowReturnOutsideFunction: true,
|
|
210
|
+
allowAwaitOutsideFunction: true,
|
|
211
|
+
locations: true
|
|
194
212
|
});
|
|
213
|
+
} catch {
|
|
214
|
+
return [];
|
|
195
215
|
}
|
|
196
|
-
|
|
197
|
-
ruleId
|
|
198
|
-
|
|
199
|
-
|
|
216
|
+
return scanDialect(program).map((finding) => {
|
|
217
|
+
const { ruleId, message } = CODEGEN_DIAGNOSTIC[finding.kind];
|
|
218
|
+
return {
|
|
219
|
+
ruleId,
|
|
220
|
+
message,
|
|
221
|
+
line: finding.line,
|
|
222
|
+
column: finding.column
|
|
223
|
+
};
|
|
200
224
|
});
|
|
201
|
-
return diagnostics;
|
|
202
225
|
}
|
|
203
226
|
/**
|
|
204
227
|
* Validates and compiles planner-generated source into a CompiledWorkflow.
|
|
@@ -216,7 +239,7 @@ function compileScript(source, o) {
|
|
|
216
239
|
}] } });
|
|
217
240
|
const blanked = blankLiterals(source);
|
|
218
241
|
diagnostics.push(...scanImports(source, blanked, allowImports));
|
|
219
|
-
diagnostics.push(...scanCodegen(source
|
|
242
|
+
diagnostics.push(...scanCodegen(source));
|
|
220
243
|
try {
|
|
221
244
|
new AsyncFunctionCtor(...SANDBOX_GLOBALS, source);
|
|
222
245
|
} catch (error) {
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { n as compileScript, r as scriptDiagnosticsOf, t as SANDBOX_GLOBALS } from "./compile-
|
|
1
|
+
import { n as compileScript, r as scriptDiagnosticsOf, t as SANDBOX_GLOBALS } from "./compile-DjzdBuva.js";
|
|
2
2
|
import { ConfigError, InMemoryStore, SANDBOX_AGENT_OPT_KEYS, SandboxError, ScriptRejected, createEngine, createSandboxBridge, defineWorkflow, readRunMeta, toJournalValue } from "@rulvar/core";
|
|
3
|
+
import { toJsonDiagnostics, workflowsConfig } from "eslint-plugin-rulvar";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
4
5
|
import { Linter } from "eslint";
|
|
5
|
-
import { toJsonDiagnostics, workflowsConfig } from "eslint-plugin-rulvar";
|
|
6
6
|
import { MessageChannel, Worker } from "node:worker_threads";
|
|
7
7
|
//#region src/api-card.ts
|
|
8
8
|
/**
|
package/dist/sandbox-worker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as SANDBOX_GLOBALS } from "./compile-
|
|
1
|
+
import { t as SANDBOX_GLOBALS } from "./compile-DjzdBuva.js";
|
|
2
2
|
import { NonSerializableValueError, toJournalValue } from "@rulvar/core";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { parentPort } from "node:worker_threads";
|
|
@@ -137,6 +137,22 @@ function main(port, init) {
|
|
|
137
137
|
Reflect.set(globalThis, "process", void 0);
|
|
138
138
|
Reflect.set(globalThis, "eval", void 0);
|
|
139
139
|
Reflect.set(globalThis, "Function", void 0);
|
|
140
|
+
const asyncProto = Object.getPrototypeOf(shimAsyncMarker);
|
|
141
|
+
const AsyncFunctionCtor = asyncProto.constructor;
|
|
142
|
+
const denyCodegen = function constructor() {
|
|
143
|
+
throw new EvalError("dynamic code generation is not available in the sandbox dialect");
|
|
144
|
+
};
|
|
145
|
+
for (const proto of [
|
|
146
|
+
Object.getPrototypeOf(shimRegularMarker),
|
|
147
|
+
asyncProto,
|
|
148
|
+
Object.getPrototypeOf(shimGeneratorMarker),
|
|
149
|
+
Object.getPrototypeOf(shimAsyncGeneratorMarker)
|
|
150
|
+
]) Object.defineProperty(proto, "constructor", {
|
|
151
|
+
value: denyCodegen,
|
|
152
|
+
writable: false,
|
|
153
|
+
enumerable: false,
|
|
154
|
+
configurable: false
|
|
155
|
+
});
|
|
140
156
|
const sandboxGlobals = {
|
|
141
157
|
agent: (prompt, opts) => callHost("agent", {
|
|
142
158
|
prompt,
|
|
@@ -270,7 +286,6 @@ function main(port, init) {
|
|
|
270
286
|
default: return;
|
|
271
287
|
}
|
|
272
288
|
});
|
|
273
|
-
const AsyncFunctionCtor = Object.getPrototypeOf(shimAsyncMarker).constructor;
|
|
274
289
|
enterFrame();
|
|
275
290
|
(async () => {
|
|
276
291
|
try {
|
|
@@ -288,8 +303,13 @@ function main(port, init) {
|
|
|
288
303
|
}
|
|
289
304
|
})();
|
|
290
305
|
}
|
|
291
|
-
/**
|
|
306
|
+
/** Markers reaching each Function family constructor prototype; never invoked. */
|
|
292
307
|
const shimAsyncMarker = async () => void 0;
|
|
308
|
+
const shimRegularMarker = () => void 0;
|
|
309
|
+
function* shimGeneratorMarker() {}
|
|
310
|
+
async function* shimAsyncGeneratorMarker() {
|
|
311
|
+
return void 0;
|
|
312
|
+
}
|
|
293
313
|
parentPort?.once("message", (init) => {
|
|
294
314
|
main(init.port, init);
|
|
295
315
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/planner",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.40.0",
|
|
4
4
|
"description": "Rulvar flagship hybrid mode: plan agent, compileScript, WorkerSandboxRunner, self-repair loop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -22,15 +22,16 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"acorn": "^8.17.0",
|
|
25
26
|
"eslint": "^9.39.4",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
27
|
+
"@rulvar/core": "1.40.0",
|
|
28
|
+
"eslint-plugin-rulvar": "1.40.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@types/node": "^22.20.0",
|
|
31
32
|
"tsdown": "^0.22.3",
|
|
32
33
|
"typescript": "~6.0.3",
|
|
33
|
-
"@rulvar/testing": "1.
|
|
34
|
+
"@rulvar/testing": "1.40.0"
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|