jules-orchestrator-kit 0.32.0 → 0.32.1
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/README.md +1 -1
- package/bin/agentctl.mjs +1 -1
- package/package.json +1 -1
- package/src/security.mjs +60 -2
- package/src/stack-detector.mjs +36 -0
package/README.md
CHANGED
|
@@ -102,7 +102,7 @@ Autonomous coding agents can write software at 100× human speed—but unconstra
|
|
|
102
102
|
|
|
103
103
|
* **🔒 Zero Runtime Dependencies:** Built exclusively on Node.js 20+ built-ins (`node:fs`, `node:child_process`, `node:crypto`, `node:path`, `node:http`, `node:tty`, `node:test`). Zero third-party npm packages mean zero supply-chain CVE risk.
|
|
104
104
|
|
|
105
|
-
* **🛡️ Fail-Closed Security Gatekeeper:** Unconditionally evaluates explicit Deny rules *before* Allow rules, redacts high-entropy secrets and PII from dry-runs and git diffs, and rejects PRs exceeding the 75 KB Diff Payload governor.
|
|
105
|
+
* **🛡️ Fail-Closed Security Gatekeeper:** Unconditionally evaluates explicit Deny rules *before* Allow rules, redacts high-entropy secrets and PII from dry-runs and git diffs, blocks unsupported Node.js native module imports in Edge environments (Cloudflare Workers, Vercel Edge, Netlify Edge), and rejects PRs exceeding the 75 KB Diff Payload governor.
|
|
106
106
|
|
|
107
107
|
* **🔄 Autonomous OODA Self-Healing:** Captures test stderr/stdout, normalizes failure fingerprints, and feeds structured error contexts back into repair iterations (up to 3 automatic attempts) before human escalation.
|
|
108
108
|
|
package/bin/agentctl.mjs
CHANGED
|
@@ -14,7 +14,7 @@ const command = args[0];
|
|
|
14
14
|
|
|
15
15
|
function printHelp() {
|
|
16
16
|
console.log(`
|
|
17
|
-
🚀 agentctl v0.32.
|
|
17
|
+
🚀 agentctl v0.32.1 — Universal Agent Orchestrator & Safety Gatekeeper
|
|
18
18
|
|
|
19
19
|
Usage: agentctl <command> [options]
|
|
20
20
|
|
package/package.json
CHANGED
package/src/security.mjs
CHANGED
|
@@ -236,7 +236,58 @@ export function checkScope(files = [], scope = {}, opts = {}) {
|
|
|
236
236
|
};
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
export
|
|
239
|
+
export const FORBIDDEN_EDGE_MODULES = [
|
|
240
|
+
"fs", "node:fs",
|
|
241
|
+
"child_process", "node:child_process",
|
|
242
|
+
"cluster", "node:cluster",
|
|
243
|
+
"dgram", "node:dgram",
|
|
244
|
+
"net", "node:net",
|
|
245
|
+
"tls", "node:tls",
|
|
246
|
+
"v8", "node:v8",
|
|
247
|
+
"vm", "node:vm",
|
|
248
|
+
"worker_threads", "node:worker_threads",
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
export function checkEdgeRuntimeImports(diffOrText = "", options = {}) {
|
|
252
|
+
if (!diffOrText || typeof diffOrText !== "string") return { ok: true, violations: [] };
|
|
253
|
+
|
|
254
|
+
const isEdgeExplicit = options.isEdgeRuntime === true;
|
|
255
|
+
const hasEdgeExport = /export\s+const\s+runtime\s*=\s*['"]edge['"]/i.test(diffOrText);
|
|
256
|
+
const isEdgeContext = isEdgeExplicit || hasEdgeExport;
|
|
257
|
+
|
|
258
|
+
if (!isEdgeContext) {
|
|
259
|
+
return { ok: true, violations: [] };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const lines = diffOrText.split("\n");
|
|
263
|
+
const targetLines = lines.filter((line) => {
|
|
264
|
+
if (diffOrText.includes("+++ b/")) {
|
|
265
|
+
return line.startsWith("+") && !line.startsWith("+++");
|
|
266
|
+
}
|
|
267
|
+
return true;
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const edgeImportRegex = /(?:import\s+.*?\s+from\s+|require\s*\(\s*)['"](node:(?:fs|child_process|cluster|dgram|net|tls|v8|vm|worker_threads)|(?:fs|child_process|cluster|dgram|net|tls|v8|vm|worker_threads))(?:\/.*)?['"]/i;
|
|
271
|
+
|
|
272
|
+
const violations = [];
|
|
273
|
+
for (const line of targetLines) {
|
|
274
|
+
const match = line.match(edgeImportRegex);
|
|
275
|
+
if (match) {
|
|
276
|
+
violations.push({
|
|
277
|
+
module: match[1],
|
|
278
|
+
line: line.trim(),
|
|
279
|
+
reason: `Edge Runtime Violation: Native Node module "${match[1]}" is unsupported in Edge environments (Cloudflare Workers / Vercel Edge / Netlify Edge).`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
ok: violations.length === 0,
|
|
286
|
+
violations,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function scanDiff(diffTextStr = "", options = {}) {
|
|
240
291
|
if (!diffTextStr) return { ok: true, findings: [] };
|
|
241
292
|
const addedLines = diffTextStr
|
|
242
293
|
.split("\n")
|
|
@@ -254,8 +305,15 @@ export function scanDiff(diffTextStr = "") {
|
|
|
254
305
|
findings.push({ severity: "HIGH", type: "LOW_CONFIDENCE_SECRET", description: "Low-confidence secret or authorization token detected in added diff lines" });
|
|
255
306
|
}
|
|
256
307
|
|
|
308
|
+
const edgeRes = checkEdgeRuntimeImports(diffTextStr, options);
|
|
309
|
+
if (!edgeRes.ok) {
|
|
310
|
+
for (const v of edgeRes.violations) {
|
|
311
|
+
findings.push({ severity: "HIGH", type: "EDGE_RUNTIME_VIOLATION", description: v.reason });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
257
315
|
return {
|
|
258
|
-
ok: !hasHigh && !hasLow,
|
|
316
|
+
ok: !hasHigh && !hasLow && edgeRes.ok,
|
|
259
317
|
findings,
|
|
260
318
|
};
|
|
261
319
|
}
|
package/src/stack-detector.mjs
CHANGED
|
@@ -26,10 +26,45 @@ test("Zero-Test Bootstrapped Smoke Verification", () => {
|
|
|
26
26
|
return ".agent/smoke.test.mjs";
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export function detectEdgeRuntime(projectRoot = process.cwd()) {
|
|
30
|
+
const isCloudflare = existsSync(join(projectRoot, "wrangler.toml")) || existsSync(join(projectRoot, "wrangler.json"));
|
|
31
|
+
const isDeno = existsSync(join(projectRoot, "deno.json")) || existsSync(join(projectRoot, "deno.jsonc"));
|
|
32
|
+
const isNetlify = existsSync(join(projectRoot, "netlify.toml"));
|
|
33
|
+
|
|
34
|
+
let isPkgEdge = false;
|
|
35
|
+
let pkgEdgePlatform = null;
|
|
36
|
+
|
|
37
|
+
const pkgPath = join(projectRoot, "package.json");
|
|
38
|
+
if (existsSync(pkgPath)) {
|
|
39
|
+
try {
|
|
40
|
+
const content = readFileSync(pkgPath, "utf-8");
|
|
41
|
+
if (content.includes("@cloudflare/workers-types") || content.includes("@cloudflare/env")) {
|
|
42
|
+
isPkgEdge = true;
|
|
43
|
+
pkgEdgePlatform = "cloudflare";
|
|
44
|
+
} else if (content.includes("@vercel/edge") || content.includes("@vercel/functions")) {
|
|
45
|
+
isPkgEdge = true;
|
|
46
|
+
pkgEdgePlatform = "vercel";
|
|
47
|
+
} else if (content.includes("@netlify/edge-functions")) {
|
|
48
|
+
isPkgEdge = true;
|
|
49
|
+
pkgEdgePlatform = "netlify";
|
|
50
|
+
}
|
|
51
|
+
} catch (_) {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isEdge = isCloudflare || isDeno || isNetlify || isPkgEdge;
|
|
55
|
+
const platform = isCloudflare ? "cloudflare" : isDeno ? "deno" : isNetlify ? "netlify" : pkgEdgePlatform;
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
isEdgeRuntime: isEdge,
|
|
59
|
+
edgePlatform: platform,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
29
63
|
/**
|
|
30
64
|
* Detects 24+ polyglot stacks and container environments.
|
|
31
65
|
*/
|
|
32
66
|
export function detectPolyglotStack(projectRoot = process.cwd()) {
|
|
67
|
+
const edgeInfo = detectEdgeRuntime(projectRoot);
|
|
33
68
|
const isDevcontainer = existsSync(join(projectRoot, ".devcontainer", "devcontainer.json"));
|
|
34
69
|
const isCompose =
|
|
35
70
|
existsSync(join(projectRoot, "docker-compose.yml")) ||
|
|
@@ -38,6 +73,7 @@ export function detectPolyglotStack(projectRoot = process.cwd()) {
|
|
|
38
73
|
existsSync(join(projectRoot, "compose.yaml"));
|
|
39
74
|
|
|
40
75
|
const container = {
|
|
76
|
+
...edgeInfo,
|
|
41
77
|
containerized: isDevcontainer || isCompose,
|
|
42
78
|
containerType: isDevcontainer ? "devcontainer" : isCompose ? "docker-compose" : null,
|
|
43
79
|
containerCmd: isDevcontainer
|