@node9/proxy 2.9.0 → 2.9.2
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/dist/cli.js +82 -36
- package/dist/cli.mjs +83 -37
- package/dist/dashboard.mjs +78 -22
- package/dist/index.js +78 -22
- package/dist/index.mjs +78 -22
- package/dist/scan-ink.mjs +7 -7
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -235,30 +235,86 @@ var init_audit = __esm({
|
|
|
235
235
|
});
|
|
236
236
|
|
|
237
237
|
// src/config-schema.ts
|
|
238
|
+
function formatIssues(issues) {
|
|
239
|
+
const lines = issues.map((issue) => {
|
|
240
|
+
const path77 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
241
|
+
return ` \u2022 ${path77}: ${issue.message}`;
|
|
242
|
+
});
|
|
243
|
+
return `Invalid config:
|
|
244
|
+
${lines.join("\n")}`;
|
|
245
|
+
}
|
|
246
|
+
function prunePaths(root, paths) {
|
|
247
|
+
let removed = false;
|
|
248
|
+
const ordered = [...paths].sort((x, y) => {
|
|
249
|
+
if (y.length !== x.length) return y.length - x.length;
|
|
250
|
+
const xi = x[x.length - 1];
|
|
251
|
+
const yi = y[y.length - 1];
|
|
252
|
+
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
253
|
+
});
|
|
254
|
+
for (const path77 of ordered) {
|
|
255
|
+
let cur = root;
|
|
256
|
+
for (const key of path77.slice(0, -1)) {
|
|
257
|
+
if (cur === null || typeof cur !== "object") {
|
|
258
|
+
cur = void 0;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
cur = cur[key];
|
|
262
|
+
}
|
|
263
|
+
if (cur === null || typeof cur !== "object") continue;
|
|
264
|
+
const last = path77[path77.length - 1];
|
|
265
|
+
if (Array.isArray(cur)) {
|
|
266
|
+
const i = Number(last);
|
|
267
|
+
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
268
|
+
cur.splice(i, 1);
|
|
269
|
+
removed = true;
|
|
270
|
+
}
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const obj = cur;
|
|
274
|
+
if (Object.prototype.hasOwnProperty.call(obj, String(last))) {
|
|
275
|
+
delete obj[String(last)];
|
|
276
|
+
removed = true;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return removed;
|
|
280
|
+
}
|
|
238
281
|
function sanitizeConfig(raw) {
|
|
239
282
|
const result = ConfigFileSchema.safeParse(raw);
|
|
240
283
|
if (result.success) {
|
|
241
284
|
return { sanitized: result.data, error: null };
|
|
242
285
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
for (
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
286
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
287
|
+
return { sanitized: {}, error: formatIssues(result.error.issues) };
|
|
288
|
+
}
|
|
289
|
+
const working = structuredClone(raw);
|
|
290
|
+
for (let level = 0; level < 6; level++) {
|
|
291
|
+
for (let pass = 0; pass < 5; pass++) {
|
|
292
|
+
const attempt = ConfigFileSchema.safeParse(working);
|
|
293
|
+
if (attempt.success) break;
|
|
294
|
+
const paths = attempt.error.issues.flatMap((issue) => {
|
|
295
|
+
const at = issue.path;
|
|
296
|
+
if (issue.code === "unrecognized_keys") {
|
|
297
|
+
return issue.keys.map((k) => [...at, k]);
|
|
298
|
+
}
|
|
299
|
+
return [at.slice(0, -level || void 0)];
|
|
300
|
+
}).filter((path77) => path77.length > 0);
|
|
301
|
+
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
252
302
|
}
|
|
303
|
+
if (ConfigFileSchema.safeParse(working).success) break;
|
|
304
|
+
}
|
|
305
|
+
const after = ConfigFileSchema.safeParse(working);
|
|
306
|
+
const sanitized = {};
|
|
307
|
+
const invalidTopLevelKeys = after.success ? /* @__PURE__ */ new Set() : new Set(
|
|
308
|
+
after.error.issues.filter((issue) => issue.path.length > 0).map((issue) => String(issue.path[0]))
|
|
309
|
+
);
|
|
310
|
+
for (const [key, value] of Object.entries(working)) {
|
|
311
|
+
if (!invalidTopLevelKeys.has(key)) sanitized[key] = value;
|
|
253
312
|
}
|
|
254
|
-
const lines = result.error.issues.map((issue) => {
|
|
255
|
-
const path77 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
256
|
-
return ` \u2022 ${path77}: ${issue.message}`;
|
|
257
|
-
});
|
|
258
313
|
return {
|
|
259
314
|
sanitized,
|
|
260
|
-
|
|
261
|
-
|
|
315
|
+
// The message names what the USER should fix, so it is built from the
|
|
316
|
+
// original parse, not from whatever survived the prune.
|
|
317
|
+
error: formatIssues(result.error.issues)
|
|
262
318
|
};
|
|
263
319
|
}
|
|
264
320
|
var import_zod, noNewlines, SmartConditionSchema, SmartRuleSchema, ConfigFileSchema;
|
|
@@ -283,9 +339,9 @@ var init_config_schema = __esm({
|
|
|
283
339
|
"notMatchesGlob"
|
|
284
340
|
],
|
|
285
341
|
{
|
|
286
|
-
errorMap
|
|
287
|
-
|
|
288
|
-
|
|
342
|
+
// zod 4 replaced errorMap with `error`. The wording is kept verbatim:
|
|
343
|
+
// it is what a user sees when their config is rejected.
|
|
344
|
+
error: () => "op must be one of: matches, notMatches, contains, notContains, exists, notExists, matchesGlob, notMatchesGlob"
|
|
289
345
|
}
|
|
290
346
|
),
|
|
291
347
|
value: import_zod.z.string().optional(),
|
|
@@ -303,7 +359,7 @@ var init_config_schema = __esm({
|
|
|
303
359
|
conditions: import_zod.z.array(SmartConditionSchema).min(1, "Smart rule must have at least one condition"),
|
|
304
360
|
conditionMode: import_zod.z.enum(["all", "any"]).optional(),
|
|
305
361
|
verdict: import_zod.z.enum(["allow", "review", "block"], {
|
|
306
|
-
|
|
362
|
+
error: () => "verdict must be one of: allow, review, block"
|
|
307
363
|
}),
|
|
308
364
|
reason: import_zod.z.string().optional(),
|
|
309
365
|
description: import_zod.z.string().optional(),
|
|
@@ -376,7 +432,7 @@ var init_config_schema = __esm({
|
|
|
376
432
|
sandboxPaths: import_zod.z.array(import_zod.z.string()).optional(),
|
|
377
433
|
dangerousWords: import_zod.z.array(noNewlines).optional(),
|
|
378
434
|
ignoredTools: import_zod.z.array(import_zod.z.string()).optional(),
|
|
379
|
-
toolInspection: import_zod.z.record(import_zod.z.string()).optional(),
|
|
435
|
+
toolInspection: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
380
436
|
smartRules: import_zod.z.array(SmartRuleSchema).optional(),
|
|
381
437
|
dlp: import_zod.z.object({
|
|
382
438
|
enabled: import_zod.z.boolean().optional(),
|
|
@@ -421,8 +477,8 @@ var init_config_schema = __esm({
|
|
|
421
477
|
roots: import_zod.z.array(import_zod.z.string()).optional()
|
|
422
478
|
}).optional()
|
|
423
479
|
}).optional(),
|
|
424
|
-
environments: import_zod.z.record(import_zod.z.object({ requireApproval: import_zod.z.boolean().optional() })).optional()
|
|
425
|
-
}).strict(
|
|
480
|
+
environments: import_zod.z.record(import_zod.z.string(), import_zod.z.object({ requireApproval: import_zod.z.boolean().optional() })).optional()
|
|
481
|
+
}).strict();
|
|
426
482
|
}
|
|
427
483
|
});
|
|
428
484
|
|
|
@@ -17287,10 +17343,7 @@ function registerScanCommand(program2) {
|
|
|
17287
17343
|
const n = scan.canaryFindings.length;
|
|
17288
17344
|
console.log(
|
|
17289
17345
|
" " + import_chalk6.default.red.bold("\u{1FAA4} Decoy Tripped") + import_chalk6.default.dim(" \xB7 ") + import_chalk6.default.red(
|
|
17290
|
-
`${num(n)} decoy credential${n !== 1 ? "s" : ""} left the file node9
|
|
17291
|
-
"planted it in",
|
|
17292
|
-
"planted it in"
|
|
17293
|
-
)
|
|
17346
|
+
`${num(n)} decoy credential${n !== 1 ? "s" : ""} left the file node9 planted it in`
|
|
17294
17347
|
)
|
|
17295
17348
|
);
|
|
17296
17349
|
const shownCanaries = drillDown ? scan.canaryFindings : scan.canaryFindings.slice(0, topN);
|
|
@@ -54430,12 +54483,7 @@ function renderTerminalReport(data, responseDlpEntries, excludeTests) {
|
|
|
54430
54483
|
`${num2(d.approvals.approved)} approved \xB7 ${num2(d.approvals.denied)} denied \xB7 ${num2(d.approvals.timedOut)} timed-out\u2192deny`
|
|
54431
54484
|
);
|
|
54432
54485
|
dimRow("\u{1F4C1}", "Files", d.files.blocked > 0, `${num2(d.files.blocked)} jail-path reads blocked`);
|
|
54433
|
-
dimRow(
|
|
54434
|
-
"\u{1F6E0}",
|
|
54435
|
-
"Tool rules",
|
|
54436
|
-
d.toolRules.blocked > 0,
|
|
54437
|
-
`${num2(d.toolRules.blocked)} shields/rules`
|
|
54438
|
-
);
|
|
54486
|
+
dimRow("\u{1F6E0}", "Tool rules", d.toolRules.blocked > 0, `${num2(d.toolRules.blocked)} shields/rules`);
|
|
54439
54487
|
dimRow("\u{1F9E9}", "Apps (MCP)", d.apps.blocked > 0, `${num2(d.apps.blocked)} app-permission blocks`);
|
|
54440
54488
|
dimRow("\u{1F4B0}", "Cost", d.cost.totalUSD > 0, `${fmtCost2(d.cost.totalUSD)} this period`);
|
|
54441
54489
|
}
|
|
@@ -59137,9 +59185,8 @@ var DB_USERS = ["app", "svc", "reporter"];
|
|
|
59137
59185
|
var DB_HOSTS = ["db-internal", "pg-primary.internal", "postgres.svc.cluster.local"];
|
|
59138
59186
|
var DB_NAMES = ["app", "prod", "main"];
|
|
59139
59187
|
var pick = (alphabet, n) => {
|
|
59140
|
-
const bytes = (0, import_crypto15.randomBytes)(n);
|
|
59141
59188
|
let out = "";
|
|
59142
|
-
for (let i = 0; i < n; i++) out += alphabet[
|
|
59189
|
+
for (let i = 0; i < n; i++) out += alphabet[(0, import_crypto15.randomInt)(alphabet.length)];
|
|
59143
59190
|
return out;
|
|
59144
59191
|
};
|
|
59145
59192
|
var choose = (xs) => xs[(0, import_crypto15.randomInt)(xs.length)];
|
|
@@ -59281,9 +59328,8 @@ function plantKind(kind, home = import_os55.default.homedir()) {
|
|
|
59281
59328
|
};
|
|
59282
59329
|
}
|
|
59283
59330
|
const dir = import_path61.default.dirname(target);
|
|
59284
|
-
const createdDir = !import_fs66.default.existsSync(dir);
|
|
59285
59331
|
const gen = site.generate();
|
|
59286
|
-
|
|
59332
|
+
const createdDir = import_fs66.default.mkdirSync(dir, { recursive: true, mode: site.dirMode }) !== void 0;
|
|
59287
59333
|
import_fs66.default.writeFileSync(target, gen.text, { mode: 384, flag: "wx" });
|
|
59288
59334
|
import_fs66.default.chmodSync(target, 384);
|
|
59289
59335
|
const fileHash = sha256Hex(gen.text);
|
package/dist/cli.mjs
CHANGED
|
@@ -240,30 +240,86 @@ var init_audit = __esm({
|
|
|
240
240
|
|
|
241
241
|
// src/config-schema.ts
|
|
242
242
|
import { z } from "zod";
|
|
243
|
+
function formatIssues(issues) {
|
|
244
|
+
const lines = issues.map((issue) => {
|
|
245
|
+
const path77 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
246
|
+
return ` \u2022 ${path77}: ${issue.message}`;
|
|
247
|
+
});
|
|
248
|
+
return `Invalid config:
|
|
249
|
+
${lines.join("\n")}`;
|
|
250
|
+
}
|
|
251
|
+
function prunePaths(root, paths) {
|
|
252
|
+
let removed = false;
|
|
253
|
+
const ordered = [...paths].sort((x, y) => {
|
|
254
|
+
if (y.length !== x.length) return y.length - x.length;
|
|
255
|
+
const xi = x[x.length - 1];
|
|
256
|
+
const yi = y[y.length - 1];
|
|
257
|
+
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
258
|
+
});
|
|
259
|
+
for (const path77 of ordered) {
|
|
260
|
+
let cur = root;
|
|
261
|
+
for (const key of path77.slice(0, -1)) {
|
|
262
|
+
if (cur === null || typeof cur !== "object") {
|
|
263
|
+
cur = void 0;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
cur = cur[key];
|
|
267
|
+
}
|
|
268
|
+
if (cur === null || typeof cur !== "object") continue;
|
|
269
|
+
const last = path77[path77.length - 1];
|
|
270
|
+
if (Array.isArray(cur)) {
|
|
271
|
+
const i = Number(last);
|
|
272
|
+
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
273
|
+
cur.splice(i, 1);
|
|
274
|
+
removed = true;
|
|
275
|
+
}
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const obj = cur;
|
|
279
|
+
if (Object.prototype.hasOwnProperty.call(obj, String(last))) {
|
|
280
|
+
delete obj[String(last)];
|
|
281
|
+
removed = true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return removed;
|
|
285
|
+
}
|
|
243
286
|
function sanitizeConfig(raw) {
|
|
244
287
|
const result = ConfigFileSchema.safeParse(raw);
|
|
245
288
|
if (result.success) {
|
|
246
289
|
return { sanitized: result.data, error: null };
|
|
247
290
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
for (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
291
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
292
|
+
return { sanitized: {}, error: formatIssues(result.error.issues) };
|
|
293
|
+
}
|
|
294
|
+
const working = structuredClone(raw);
|
|
295
|
+
for (let level = 0; level < 6; level++) {
|
|
296
|
+
for (let pass = 0; pass < 5; pass++) {
|
|
297
|
+
const attempt = ConfigFileSchema.safeParse(working);
|
|
298
|
+
if (attempt.success) break;
|
|
299
|
+
const paths = attempt.error.issues.flatMap((issue) => {
|
|
300
|
+
const at = issue.path;
|
|
301
|
+
if (issue.code === "unrecognized_keys") {
|
|
302
|
+
return issue.keys.map((k) => [...at, k]);
|
|
303
|
+
}
|
|
304
|
+
return [at.slice(0, -level || void 0)];
|
|
305
|
+
}).filter((path77) => path77.length > 0);
|
|
306
|
+
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
257
307
|
}
|
|
308
|
+
if (ConfigFileSchema.safeParse(working).success) break;
|
|
309
|
+
}
|
|
310
|
+
const after = ConfigFileSchema.safeParse(working);
|
|
311
|
+
const sanitized = {};
|
|
312
|
+
const invalidTopLevelKeys = after.success ? /* @__PURE__ */ new Set() : new Set(
|
|
313
|
+
after.error.issues.filter((issue) => issue.path.length > 0).map((issue) => String(issue.path[0]))
|
|
314
|
+
);
|
|
315
|
+
for (const [key, value] of Object.entries(working)) {
|
|
316
|
+
if (!invalidTopLevelKeys.has(key)) sanitized[key] = value;
|
|
258
317
|
}
|
|
259
|
-
const lines = result.error.issues.map((issue) => {
|
|
260
|
-
const path77 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
261
|
-
return ` \u2022 ${path77}: ${issue.message}`;
|
|
262
|
-
});
|
|
263
318
|
return {
|
|
264
319
|
sanitized,
|
|
265
|
-
|
|
266
|
-
|
|
320
|
+
// The message names what the USER should fix, so it is built from the
|
|
321
|
+
// original parse, not from whatever survived the prune.
|
|
322
|
+
error: formatIssues(result.error.issues)
|
|
267
323
|
};
|
|
268
324
|
}
|
|
269
325
|
var noNewlines, SmartConditionSchema, SmartRuleSchema, ConfigFileSchema;
|
|
@@ -287,9 +343,9 @@ var init_config_schema = __esm({
|
|
|
287
343
|
"notMatchesGlob"
|
|
288
344
|
],
|
|
289
345
|
{
|
|
290
|
-
errorMap
|
|
291
|
-
|
|
292
|
-
|
|
346
|
+
// zod 4 replaced errorMap with `error`. The wording is kept verbatim:
|
|
347
|
+
// it is what a user sees when their config is rejected.
|
|
348
|
+
error: () => "op must be one of: matches, notMatches, contains, notContains, exists, notExists, matchesGlob, notMatchesGlob"
|
|
293
349
|
}
|
|
294
350
|
),
|
|
295
351
|
value: z.string().optional(),
|
|
@@ -307,7 +363,7 @@ var init_config_schema = __esm({
|
|
|
307
363
|
conditions: z.array(SmartConditionSchema).min(1, "Smart rule must have at least one condition"),
|
|
308
364
|
conditionMode: z.enum(["all", "any"]).optional(),
|
|
309
365
|
verdict: z.enum(["allow", "review", "block"], {
|
|
310
|
-
|
|
366
|
+
error: () => "verdict must be one of: allow, review, block"
|
|
311
367
|
}),
|
|
312
368
|
reason: z.string().optional(),
|
|
313
369
|
description: z.string().optional(),
|
|
@@ -380,7 +436,7 @@ var init_config_schema = __esm({
|
|
|
380
436
|
sandboxPaths: z.array(z.string()).optional(),
|
|
381
437
|
dangerousWords: z.array(noNewlines).optional(),
|
|
382
438
|
ignoredTools: z.array(z.string()).optional(),
|
|
383
|
-
toolInspection: z.record(z.string()).optional(),
|
|
439
|
+
toolInspection: z.record(z.string(), z.string()).optional(),
|
|
384
440
|
smartRules: z.array(SmartRuleSchema).optional(),
|
|
385
441
|
dlp: z.object({
|
|
386
442
|
enabled: z.boolean().optional(),
|
|
@@ -425,8 +481,8 @@ var init_config_schema = __esm({
|
|
|
425
481
|
roots: z.array(z.string()).optional()
|
|
426
482
|
}).optional()
|
|
427
483
|
}).optional(),
|
|
428
|
-
environments: z.record(z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
429
|
-
}).strict(
|
|
484
|
+
environments: z.record(z.string(), z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
485
|
+
}).strict();
|
|
430
486
|
}
|
|
431
487
|
});
|
|
432
488
|
|
|
@@ -17291,10 +17347,7 @@ function registerScanCommand(program2) {
|
|
|
17291
17347
|
const n = scan.canaryFindings.length;
|
|
17292
17348
|
console.log(
|
|
17293
17349
|
" " + chalk6.red.bold("\u{1FAA4} Decoy Tripped") + chalk6.dim(" \xB7 ") + chalk6.red(
|
|
17294
|
-
`${num(n)} decoy credential${n !== 1 ? "s" : ""} left the file node9
|
|
17295
|
-
"planted it in",
|
|
17296
|
-
"planted it in"
|
|
17297
|
-
)
|
|
17350
|
+
`${num(n)} decoy credential${n !== 1 ? "s" : ""} left the file node9 planted it in`
|
|
17298
17351
|
)
|
|
17299
17352
|
);
|
|
17300
17353
|
const shownCanaries = drillDown ? scan.canaryFindings : scan.canaryFindings.slice(0, topN);
|
|
@@ -54422,12 +54475,7 @@ function renderTerminalReport(data, responseDlpEntries, excludeTests) {
|
|
|
54422
54475
|
`${num2(d.approvals.approved)} approved \xB7 ${num2(d.approvals.denied)} denied \xB7 ${num2(d.approvals.timedOut)} timed-out\u2192deny`
|
|
54423
54476
|
);
|
|
54424
54477
|
dimRow("\u{1F4C1}", "Files", d.files.blocked > 0, `${num2(d.files.blocked)} jail-path reads blocked`);
|
|
54425
|
-
dimRow(
|
|
54426
|
-
"\u{1F6E0}",
|
|
54427
|
-
"Tool rules",
|
|
54428
|
-
d.toolRules.blocked > 0,
|
|
54429
|
-
`${num2(d.toolRules.blocked)} shields/rules`
|
|
54430
|
-
);
|
|
54478
|
+
dimRow("\u{1F6E0}", "Tool rules", d.toolRules.blocked > 0, `${num2(d.toolRules.blocked)} shields/rules`);
|
|
54431
54479
|
dimRow("\u{1F9E9}", "Apps (MCP)", d.apps.blocked > 0, `${num2(d.apps.blocked)} app-permission blocks`);
|
|
54432
54480
|
dimRow("\u{1F4B0}", "Cost", d.cost.totalUSD > 0, `${fmtCost2(d.cost.totalUSD)} this period`);
|
|
54433
54481
|
}
|
|
@@ -59113,7 +59161,7 @@ import path64 from "path";
|
|
|
59113
59161
|
|
|
59114
59162
|
// src/canary/generate.ts
|
|
59115
59163
|
init_dlp();
|
|
59116
|
-
import {
|
|
59164
|
+
import { randomInt } from "crypto";
|
|
59117
59165
|
var ALPHA_B32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
59118
59166
|
var ALPHA_ALNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
59119
59167
|
var ALPHA_B64 = ALPHA_ALNUM + "+/";
|
|
@@ -59129,9 +59177,8 @@ var DB_USERS = ["app", "svc", "reporter"];
|
|
|
59129
59177
|
var DB_HOSTS = ["db-internal", "pg-primary.internal", "postgres.svc.cluster.local"];
|
|
59130
59178
|
var DB_NAMES = ["app", "prod", "main"];
|
|
59131
59179
|
var pick = (alphabet, n) => {
|
|
59132
|
-
const bytes = randomBytes2(n);
|
|
59133
59180
|
let out = "";
|
|
59134
|
-
for (let i = 0; i < n; i++) out += alphabet[
|
|
59181
|
+
for (let i = 0; i < n; i++) out += alphabet[randomInt(alphabet.length)];
|
|
59135
59182
|
return out;
|
|
59136
59183
|
};
|
|
59137
59184
|
var choose = (xs) => xs[randomInt(xs.length)];
|
|
@@ -59273,9 +59320,8 @@ function plantKind(kind, home = os59.homedir()) {
|
|
|
59273
59320
|
};
|
|
59274
59321
|
}
|
|
59275
59322
|
const dir = path65.dirname(target);
|
|
59276
|
-
const createdDir = !fs70.existsSync(dir);
|
|
59277
59323
|
const gen = site.generate();
|
|
59278
|
-
|
|
59324
|
+
const createdDir = fs70.mkdirSync(dir, { recursive: true, mode: site.dirMode }) !== void 0;
|
|
59279
59325
|
fs70.writeFileSync(target, gen.text, { mode: 384, flag: "wx" });
|
|
59280
59326
|
fs70.chmodSync(target, 384);
|
|
59281
59327
|
const fileHash = sha256Hex(gen.text);
|
package/dist/dashboard.mjs
CHANGED
|
@@ -2737,30 +2737,86 @@ var init_daemon = __esm({
|
|
|
2737
2737
|
|
|
2738
2738
|
// src/config-schema.ts
|
|
2739
2739
|
import { z } from "zod";
|
|
2740
|
+
function formatIssues(issues) {
|
|
2741
|
+
const lines = issues.map((issue) => {
|
|
2742
|
+
const path14 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
2743
|
+
return ` \u2022 ${path14}: ${issue.message}`;
|
|
2744
|
+
});
|
|
2745
|
+
return `Invalid config:
|
|
2746
|
+
${lines.join("\n")}`;
|
|
2747
|
+
}
|
|
2748
|
+
function prunePaths(root, paths) {
|
|
2749
|
+
let removed = false;
|
|
2750
|
+
const ordered = [...paths].sort((x, y) => {
|
|
2751
|
+
if (y.length !== x.length) return y.length - x.length;
|
|
2752
|
+
const xi = x[x.length - 1];
|
|
2753
|
+
const yi = y[y.length - 1];
|
|
2754
|
+
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
2755
|
+
});
|
|
2756
|
+
for (const path14 of ordered) {
|
|
2757
|
+
let cur = root;
|
|
2758
|
+
for (const key of path14.slice(0, -1)) {
|
|
2759
|
+
if (cur === null || typeof cur !== "object") {
|
|
2760
|
+
cur = void 0;
|
|
2761
|
+
break;
|
|
2762
|
+
}
|
|
2763
|
+
cur = cur[key];
|
|
2764
|
+
}
|
|
2765
|
+
if (cur === null || typeof cur !== "object") continue;
|
|
2766
|
+
const last = path14[path14.length - 1];
|
|
2767
|
+
if (Array.isArray(cur)) {
|
|
2768
|
+
const i = Number(last);
|
|
2769
|
+
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
2770
|
+
cur.splice(i, 1);
|
|
2771
|
+
removed = true;
|
|
2772
|
+
}
|
|
2773
|
+
continue;
|
|
2774
|
+
}
|
|
2775
|
+
const obj = cur;
|
|
2776
|
+
if (Object.prototype.hasOwnProperty.call(obj, String(last))) {
|
|
2777
|
+
delete obj[String(last)];
|
|
2778
|
+
removed = true;
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
return removed;
|
|
2782
|
+
}
|
|
2740
2783
|
function sanitizeConfig(raw) {
|
|
2741
2784
|
const result = ConfigFileSchema.safeParse(raw);
|
|
2742
2785
|
if (result.success) {
|
|
2743
2786
|
return { sanitized: result.data, error: null };
|
|
2744
2787
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
const
|
|
2749
|
-
|
|
2750
|
-
for (
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2788
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
2789
|
+
return { sanitized: {}, error: formatIssues(result.error.issues) };
|
|
2790
|
+
}
|
|
2791
|
+
const working = structuredClone(raw);
|
|
2792
|
+
for (let level = 0; level < 6; level++) {
|
|
2793
|
+
for (let pass = 0; pass < 5; pass++) {
|
|
2794
|
+
const attempt = ConfigFileSchema.safeParse(working);
|
|
2795
|
+
if (attempt.success) break;
|
|
2796
|
+
const paths = attempt.error.issues.flatMap((issue) => {
|
|
2797
|
+
const at = issue.path;
|
|
2798
|
+
if (issue.code === "unrecognized_keys") {
|
|
2799
|
+
return issue.keys.map((k) => [...at, k]);
|
|
2800
|
+
}
|
|
2801
|
+
return [at.slice(0, -level || void 0)];
|
|
2802
|
+
}).filter((path14) => path14.length > 0);
|
|
2803
|
+
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
2754
2804
|
}
|
|
2805
|
+
if (ConfigFileSchema.safeParse(working).success) break;
|
|
2806
|
+
}
|
|
2807
|
+
const after = ConfigFileSchema.safeParse(working);
|
|
2808
|
+
const sanitized = {};
|
|
2809
|
+
const invalidTopLevelKeys = after.success ? /* @__PURE__ */ new Set() : new Set(
|
|
2810
|
+
after.error.issues.filter((issue) => issue.path.length > 0).map((issue) => String(issue.path[0]))
|
|
2811
|
+
);
|
|
2812
|
+
for (const [key, value] of Object.entries(working)) {
|
|
2813
|
+
if (!invalidTopLevelKeys.has(key)) sanitized[key] = value;
|
|
2755
2814
|
}
|
|
2756
|
-
const lines = result.error.issues.map((issue) => {
|
|
2757
|
-
const path14 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
2758
|
-
return ` \u2022 ${path14}: ${issue.message}`;
|
|
2759
|
-
});
|
|
2760
2815
|
return {
|
|
2761
2816
|
sanitized,
|
|
2762
|
-
|
|
2763
|
-
|
|
2817
|
+
// The message names what the USER should fix, so it is built from the
|
|
2818
|
+
// original parse, not from whatever survived the prune.
|
|
2819
|
+
error: formatIssues(result.error.issues)
|
|
2764
2820
|
};
|
|
2765
2821
|
}
|
|
2766
2822
|
var noNewlines, SmartConditionSchema, SmartRuleSchema, ConfigFileSchema;
|
|
@@ -2784,9 +2840,9 @@ var init_config_schema = __esm({
|
|
|
2784
2840
|
"notMatchesGlob"
|
|
2785
2841
|
],
|
|
2786
2842
|
{
|
|
2787
|
-
errorMap
|
|
2788
|
-
|
|
2789
|
-
|
|
2843
|
+
// zod 4 replaced errorMap with `error`. The wording is kept verbatim:
|
|
2844
|
+
// it is what a user sees when their config is rejected.
|
|
2845
|
+
error: () => "op must be one of: matches, notMatches, contains, notContains, exists, notExists, matchesGlob, notMatchesGlob"
|
|
2790
2846
|
}
|
|
2791
2847
|
),
|
|
2792
2848
|
value: z.string().optional(),
|
|
@@ -2804,7 +2860,7 @@ var init_config_schema = __esm({
|
|
|
2804
2860
|
conditions: z.array(SmartConditionSchema).min(1, "Smart rule must have at least one condition"),
|
|
2805
2861
|
conditionMode: z.enum(["all", "any"]).optional(),
|
|
2806
2862
|
verdict: z.enum(["allow", "review", "block"], {
|
|
2807
|
-
|
|
2863
|
+
error: () => "verdict must be one of: allow, review, block"
|
|
2808
2864
|
}),
|
|
2809
2865
|
reason: z.string().optional(),
|
|
2810
2866
|
description: z.string().optional(),
|
|
@@ -2877,7 +2933,7 @@ var init_config_schema = __esm({
|
|
|
2877
2933
|
sandboxPaths: z.array(z.string()).optional(),
|
|
2878
2934
|
dangerousWords: z.array(noNewlines).optional(),
|
|
2879
2935
|
ignoredTools: z.array(z.string()).optional(),
|
|
2880
|
-
toolInspection: z.record(z.string()).optional(),
|
|
2936
|
+
toolInspection: z.record(z.string(), z.string()).optional(),
|
|
2881
2937
|
smartRules: z.array(SmartRuleSchema).optional(),
|
|
2882
2938
|
dlp: z.object({
|
|
2883
2939
|
enabled: z.boolean().optional(),
|
|
@@ -2922,8 +2978,8 @@ var init_config_schema = __esm({
|
|
|
2922
2978
|
roots: z.array(z.string()).optional()
|
|
2923
2979
|
}).optional()
|
|
2924
2980
|
}).optional(),
|
|
2925
|
-
environments: z.record(z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
2926
|
-
}).strict(
|
|
2981
|
+
environments: z.record(z.string(), z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
2982
|
+
}).strict();
|
|
2927
2983
|
}
|
|
2928
2984
|
});
|
|
2929
2985
|
|
package/dist/index.js
CHANGED
|
@@ -265,9 +265,9 @@ var SmartConditionSchema = import_zod.z.object({
|
|
|
265
265
|
"notMatchesGlob"
|
|
266
266
|
],
|
|
267
267
|
{
|
|
268
|
-
errorMap
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
// zod 4 replaced errorMap with `error`. The wording is kept verbatim:
|
|
269
|
+
// it is what a user sees when their config is rejected.
|
|
270
|
+
error: () => "op must be one of: matches, notMatches, contains, notContains, exists, notExists, matchesGlob, notMatchesGlob"
|
|
271
271
|
}
|
|
272
272
|
),
|
|
273
273
|
value: import_zod.z.string().optional(),
|
|
@@ -285,7 +285,7 @@ var SmartRuleSchema = import_zod.z.object({
|
|
|
285
285
|
conditions: import_zod.z.array(SmartConditionSchema).min(1, "Smart rule must have at least one condition"),
|
|
286
286
|
conditionMode: import_zod.z.enum(["all", "any"]).optional(),
|
|
287
287
|
verdict: import_zod.z.enum(["allow", "review", "block"], {
|
|
288
|
-
|
|
288
|
+
error: () => "verdict must be one of: allow, review, block"
|
|
289
289
|
}),
|
|
290
290
|
reason: import_zod.z.string().optional(),
|
|
291
291
|
description: import_zod.z.string().optional(),
|
|
@@ -358,7 +358,7 @@ var ConfigFileSchema = import_zod.z.object({
|
|
|
358
358
|
sandboxPaths: import_zod.z.array(import_zod.z.string()).optional(),
|
|
359
359
|
dangerousWords: import_zod.z.array(noNewlines).optional(),
|
|
360
360
|
ignoredTools: import_zod.z.array(import_zod.z.string()).optional(),
|
|
361
|
-
toolInspection: import_zod.z.record(import_zod.z.string()).optional(),
|
|
361
|
+
toolInspection: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
362
362
|
smartRules: import_zod.z.array(SmartRuleSchema).optional(),
|
|
363
363
|
dlp: import_zod.z.object({
|
|
364
364
|
enabled: import_zod.z.boolean().optional(),
|
|
@@ -403,32 +403,88 @@ var ConfigFileSchema = import_zod.z.object({
|
|
|
403
403
|
roots: import_zod.z.array(import_zod.z.string()).optional()
|
|
404
404
|
}).optional()
|
|
405
405
|
}).optional(),
|
|
406
|
-
environments: import_zod.z.record(import_zod.z.object({ requireApproval: import_zod.z.boolean().optional() })).optional()
|
|
407
|
-
}).strict(
|
|
406
|
+
environments: import_zod.z.record(import_zod.z.string(), import_zod.z.object({ requireApproval: import_zod.z.boolean().optional() })).optional()
|
|
407
|
+
}).strict();
|
|
408
|
+
function formatIssues(issues) {
|
|
409
|
+
const lines = issues.map((issue) => {
|
|
410
|
+
const path15 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
411
|
+
return ` \u2022 ${path15}: ${issue.message}`;
|
|
412
|
+
});
|
|
413
|
+
return `Invalid config:
|
|
414
|
+
${lines.join("\n")}`;
|
|
415
|
+
}
|
|
416
|
+
function prunePaths(root, paths) {
|
|
417
|
+
let removed = false;
|
|
418
|
+
const ordered = [...paths].sort((x, y) => {
|
|
419
|
+
if (y.length !== x.length) return y.length - x.length;
|
|
420
|
+
const xi = x[x.length - 1];
|
|
421
|
+
const yi = y[y.length - 1];
|
|
422
|
+
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
423
|
+
});
|
|
424
|
+
for (const path15 of ordered) {
|
|
425
|
+
let cur = root;
|
|
426
|
+
for (const key of path15.slice(0, -1)) {
|
|
427
|
+
if (cur === null || typeof cur !== "object") {
|
|
428
|
+
cur = void 0;
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
cur = cur[key];
|
|
432
|
+
}
|
|
433
|
+
if (cur === null || typeof cur !== "object") continue;
|
|
434
|
+
const last = path15[path15.length - 1];
|
|
435
|
+
if (Array.isArray(cur)) {
|
|
436
|
+
const i = Number(last);
|
|
437
|
+
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
438
|
+
cur.splice(i, 1);
|
|
439
|
+
removed = true;
|
|
440
|
+
}
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
const obj = cur;
|
|
444
|
+
if (Object.prototype.hasOwnProperty.call(obj, String(last))) {
|
|
445
|
+
delete obj[String(last)];
|
|
446
|
+
removed = true;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return removed;
|
|
450
|
+
}
|
|
408
451
|
function sanitizeConfig(raw) {
|
|
409
452
|
const result = ConfigFileSchema.safeParse(raw);
|
|
410
453
|
if (result.success) {
|
|
411
454
|
return { sanitized: result.data, error: null };
|
|
412
455
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
for (
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
456
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
457
|
+
return { sanitized: {}, error: formatIssues(result.error.issues) };
|
|
458
|
+
}
|
|
459
|
+
const working = structuredClone(raw);
|
|
460
|
+
for (let level = 0; level < 6; level++) {
|
|
461
|
+
for (let pass = 0; pass < 5; pass++) {
|
|
462
|
+
const attempt = ConfigFileSchema.safeParse(working);
|
|
463
|
+
if (attempt.success) break;
|
|
464
|
+
const paths = attempt.error.issues.flatMap((issue) => {
|
|
465
|
+
const at = issue.path;
|
|
466
|
+
if (issue.code === "unrecognized_keys") {
|
|
467
|
+
return issue.keys.map((k) => [...at, k]);
|
|
468
|
+
}
|
|
469
|
+
return [at.slice(0, -level || void 0)];
|
|
470
|
+
}).filter((path15) => path15.length > 0);
|
|
471
|
+
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
422
472
|
}
|
|
473
|
+
if (ConfigFileSchema.safeParse(working).success) break;
|
|
474
|
+
}
|
|
475
|
+
const after = ConfigFileSchema.safeParse(working);
|
|
476
|
+
const sanitized = {};
|
|
477
|
+
const invalidTopLevelKeys = after.success ? /* @__PURE__ */ new Set() : new Set(
|
|
478
|
+
after.error.issues.filter((issue) => issue.path.length > 0).map((issue) => String(issue.path[0]))
|
|
479
|
+
);
|
|
480
|
+
for (const [key, value] of Object.entries(working)) {
|
|
481
|
+
if (!invalidTopLevelKeys.has(key)) sanitized[key] = value;
|
|
423
482
|
}
|
|
424
|
-
const lines = result.error.issues.map((issue) => {
|
|
425
|
-
const path15 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
426
|
-
return ` \u2022 ${path15}: ${issue.message}`;
|
|
427
|
-
});
|
|
428
483
|
return {
|
|
429
484
|
sanitized,
|
|
430
|
-
|
|
431
|
-
|
|
485
|
+
// The message names what the USER should fix, so it is built from the
|
|
486
|
+
// original parse, not from whatever survived the prune.
|
|
487
|
+
error: formatIssues(result.error.issues)
|
|
432
488
|
};
|
|
433
489
|
}
|
|
434
490
|
|
package/dist/index.mjs
CHANGED
|
@@ -235,9 +235,9 @@ var SmartConditionSchema = z.object({
|
|
|
235
235
|
"notMatchesGlob"
|
|
236
236
|
],
|
|
237
237
|
{
|
|
238
|
-
errorMap
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
// zod 4 replaced errorMap with `error`. The wording is kept verbatim:
|
|
239
|
+
// it is what a user sees when their config is rejected.
|
|
240
|
+
error: () => "op must be one of: matches, notMatches, contains, notContains, exists, notExists, matchesGlob, notMatchesGlob"
|
|
241
241
|
}
|
|
242
242
|
),
|
|
243
243
|
value: z.string().optional(),
|
|
@@ -255,7 +255,7 @@ var SmartRuleSchema = z.object({
|
|
|
255
255
|
conditions: z.array(SmartConditionSchema).min(1, "Smart rule must have at least one condition"),
|
|
256
256
|
conditionMode: z.enum(["all", "any"]).optional(),
|
|
257
257
|
verdict: z.enum(["allow", "review", "block"], {
|
|
258
|
-
|
|
258
|
+
error: () => "verdict must be one of: allow, review, block"
|
|
259
259
|
}),
|
|
260
260
|
reason: z.string().optional(),
|
|
261
261
|
description: z.string().optional(),
|
|
@@ -328,7 +328,7 @@ var ConfigFileSchema = z.object({
|
|
|
328
328
|
sandboxPaths: z.array(z.string()).optional(),
|
|
329
329
|
dangerousWords: z.array(noNewlines).optional(),
|
|
330
330
|
ignoredTools: z.array(z.string()).optional(),
|
|
331
|
-
toolInspection: z.record(z.string()).optional(),
|
|
331
|
+
toolInspection: z.record(z.string(), z.string()).optional(),
|
|
332
332
|
smartRules: z.array(SmartRuleSchema).optional(),
|
|
333
333
|
dlp: z.object({
|
|
334
334
|
enabled: z.boolean().optional(),
|
|
@@ -373,32 +373,88 @@ var ConfigFileSchema = z.object({
|
|
|
373
373
|
roots: z.array(z.string()).optional()
|
|
374
374
|
}).optional()
|
|
375
375
|
}).optional(),
|
|
376
|
-
environments: z.record(z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
377
|
-
}).strict(
|
|
376
|
+
environments: z.record(z.string(), z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
377
|
+
}).strict();
|
|
378
|
+
function formatIssues(issues) {
|
|
379
|
+
const lines = issues.map((issue) => {
|
|
380
|
+
const path15 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
381
|
+
return ` \u2022 ${path15}: ${issue.message}`;
|
|
382
|
+
});
|
|
383
|
+
return `Invalid config:
|
|
384
|
+
${lines.join("\n")}`;
|
|
385
|
+
}
|
|
386
|
+
function prunePaths(root, paths) {
|
|
387
|
+
let removed = false;
|
|
388
|
+
const ordered = [...paths].sort((x, y) => {
|
|
389
|
+
if (y.length !== x.length) return y.length - x.length;
|
|
390
|
+
const xi = x[x.length - 1];
|
|
391
|
+
const yi = y[y.length - 1];
|
|
392
|
+
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
393
|
+
});
|
|
394
|
+
for (const path15 of ordered) {
|
|
395
|
+
let cur = root;
|
|
396
|
+
for (const key of path15.slice(0, -1)) {
|
|
397
|
+
if (cur === null || typeof cur !== "object") {
|
|
398
|
+
cur = void 0;
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
cur = cur[key];
|
|
402
|
+
}
|
|
403
|
+
if (cur === null || typeof cur !== "object") continue;
|
|
404
|
+
const last = path15[path15.length - 1];
|
|
405
|
+
if (Array.isArray(cur)) {
|
|
406
|
+
const i = Number(last);
|
|
407
|
+
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
408
|
+
cur.splice(i, 1);
|
|
409
|
+
removed = true;
|
|
410
|
+
}
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const obj = cur;
|
|
414
|
+
if (Object.prototype.hasOwnProperty.call(obj, String(last))) {
|
|
415
|
+
delete obj[String(last)];
|
|
416
|
+
removed = true;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return removed;
|
|
420
|
+
}
|
|
378
421
|
function sanitizeConfig(raw) {
|
|
379
422
|
const result = ConfigFileSchema.safeParse(raw);
|
|
380
423
|
if (result.success) {
|
|
381
424
|
return { sanitized: result.data, error: null };
|
|
382
425
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
for (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
426
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
427
|
+
return { sanitized: {}, error: formatIssues(result.error.issues) };
|
|
428
|
+
}
|
|
429
|
+
const working = structuredClone(raw);
|
|
430
|
+
for (let level = 0; level < 6; level++) {
|
|
431
|
+
for (let pass = 0; pass < 5; pass++) {
|
|
432
|
+
const attempt = ConfigFileSchema.safeParse(working);
|
|
433
|
+
if (attempt.success) break;
|
|
434
|
+
const paths = attempt.error.issues.flatMap((issue) => {
|
|
435
|
+
const at = issue.path;
|
|
436
|
+
if (issue.code === "unrecognized_keys") {
|
|
437
|
+
return issue.keys.map((k) => [...at, k]);
|
|
438
|
+
}
|
|
439
|
+
return [at.slice(0, -level || void 0)];
|
|
440
|
+
}).filter((path15) => path15.length > 0);
|
|
441
|
+
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
392
442
|
}
|
|
443
|
+
if (ConfigFileSchema.safeParse(working).success) break;
|
|
444
|
+
}
|
|
445
|
+
const after = ConfigFileSchema.safeParse(working);
|
|
446
|
+
const sanitized = {};
|
|
447
|
+
const invalidTopLevelKeys = after.success ? /* @__PURE__ */ new Set() : new Set(
|
|
448
|
+
after.error.issues.filter((issue) => issue.path.length > 0).map((issue) => String(issue.path[0]))
|
|
449
|
+
);
|
|
450
|
+
for (const [key, value] of Object.entries(working)) {
|
|
451
|
+
if (!invalidTopLevelKeys.has(key)) sanitized[key] = value;
|
|
393
452
|
}
|
|
394
|
-
const lines = result.error.issues.map((issue) => {
|
|
395
|
-
const path15 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
396
|
-
return ` \u2022 ${path15}: ${issue.message}`;
|
|
397
|
-
});
|
|
398
453
|
return {
|
|
399
454
|
sanitized,
|
|
400
|
-
|
|
401
|
-
|
|
455
|
+
// The message names what the USER should fix, so it is built from the
|
|
456
|
+
// original parse, not from whatever survived the prune.
|
|
457
|
+
error: formatIssues(result.error.issues)
|
|
402
458
|
};
|
|
403
459
|
}
|
|
404
460
|
|
package/dist/scan-ink.mjs
CHANGED
|
@@ -61,9 +61,9 @@ var SmartConditionSchema = z.object({
|
|
|
61
61
|
"notMatchesGlob"
|
|
62
62
|
],
|
|
63
63
|
{
|
|
64
|
-
errorMap
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
// zod 4 replaced errorMap with `error`. The wording is kept verbatim:
|
|
65
|
+
// it is what a user sees when their config is rejected.
|
|
66
|
+
error: () => "op must be one of: matches, notMatches, contains, notContains, exists, notExists, matchesGlob, notMatchesGlob"
|
|
67
67
|
}
|
|
68
68
|
),
|
|
69
69
|
value: z.string().optional(),
|
|
@@ -81,7 +81,7 @@ var SmartRuleSchema = z.object({
|
|
|
81
81
|
conditions: z.array(SmartConditionSchema).min(1, "Smart rule must have at least one condition"),
|
|
82
82
|
conditionMode: z.enum(["all", "any"]).optional(),
|
|
83
83
|
verdict: z.enum(["allow", "review", "block"], {
|
|
84
|
-
|
|
84
|
+
error: () => "verdict must be one of: allow, review, block"
|
|
85
85
|
}),
|
|
86
86
|
reason: z.string().optional(),
|
|
87
87
|
description: z.string().optional(),
|
|
@@ -154,7 +154,7 @@ var ConfigFileSchema = z.object({
|
|
|
154
154
|
sandboxPaths: z.array(z.string()).optional(),
|
|
155
155
|
dangerousWords: z.array(noNewlines).optional(),
|
|
156
156
|
ignoredTools: z.array(z.string()).optional(),
|
|
157
|
-
toolInspection: z.record(z.string()).optional(),
|
|
157
|
+
toolInspection: z.record(z.string(), z.string()).optional(),
|
|
158
158
|
smartRules: z.array(SmartRuleSchema).optional(),
|
|
159
159
|
dlp: z.object({
|
|
160
160
|
enabled: z.boolean().optional(),
|
|
@@ -199,8 +199,8 @@ var ConfigFileSchema = z.object({
|
|
|
199
199
|
roots: z.array(z.string()).optional()
|
|
200
200
|
}).optional()
|
|
201
201
|
}).optional(),
|
|
202
|
-
environments: z.record(z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
203
|
-
}).strict(
|
|
202
|
+
environments: z.record(z.string(), z.object({ requireApproval: z.boolean().optional() })).optional()
|
|
203
|
+
}).strict();
|
|
204
204
|
|
|
205
205
|
// src/shields.ts
|
|
206
206
|
import fs from "fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.2",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -94,23 +94,23 @@
|
|
|
94
94
|
"smol-toml": "^1.6.1",
|
|
95
95
|
"string-width": "^4.2.3",
|
|
96
96
|
"yaml": "^2.9.0",
|
|
97
|
-
"zod": "^
|
|
97
|
+
"zod": "^4.5.4"
|
|
98
98
|
},
|
|
99
99
|
"bundleDependencies": [
|
|
100
100
|
"mvdan-sh"
|
|
101
101
|
],
|
|
102
102
|
"devDependencies": {
|
|
103
|
-
"@anthropic-ai/sdk": "^0.
|
|
103
|
+
"@anthropic-ai/sdk": "^0.124.0",
|
|
104
104
|
"@octokit/rest": "^22.0.1",
|
|
105
105
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
106
106
|
"@semantic-release/git": "^10.0.1",
|
|
107
107
|
"@semantic-release/github": "^12.0.6",
|
|
108
108
|
"@semantic-release/npm": "^13.1.5",
|
|
109
109
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
110
|
-
"@types/node": "^
|
|
110
|
+
"@types/node": "^26.4.1",
|
|
111
111
|
"@types/picomatch": "^4.0.2",
|
|
112
112
|
"@types/react": "^19.2.14",
|
|
113
|
-
"@vitest/coverage-v8": "
|
|
113
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
114
114
|
"cross-env": "^10.1.0",
|
|
115
115
|
"ink-testing-library": "^4.0.0",
|
|
116
116
|
"prettier": "^3.4.2",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"tsx": "^4.21.0",
|
|
120
120
|
"typescript": "^5.9.3",
|
|
121
121
|
"typescript-eslint": "^8.20.0",
|
|
122
|
-
"vitest": "
|
|
122
|
+
"vitest": "^5.0.0"
|
|
123
123
|
},
|
|
124
124
|
"overrides": {
|
|
125
125
|
"undici": "^7.24.0",
|