@node9/proxy 1.10.0 → 1.10.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/dist/cli.js +507 -273
- package/dist/cli.mjs +503 -269
- package/dist/index.js +31 -15
- package/dist/index.mjs +31 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -238,7 +238,8 @@ var ConfigFileSchema = import_zod.z.object({
|
|
|
238
238
|
slackEnabled: import_zod.z.boolean().optional(),
|
|
239
239
|
enableTrustSessions: import_zod.z.boolean().optional(),
|
|
240
240
|
allowGlobalPause: import_zod.z.boolean().optional(),
|
|
241
|
-
auditHashArgs: import_zod.z.boolean().optional()
|
|
241
|
+
auditHashArgs: import_zod.z.boolean().optional(),
|
|
242
|
+
agentPolicy: import_zod.z.enum(["require_approval", "block_on_rules"]).optional()
|
|
242
243
|
}).optional(),
|
|
243
244
|
policy: import_zod.z.object({
|
|
244
245
|
sandboxPaths: import_zod.z.array(import_zod.z.string()).optional(),
|
|
@@ -2321,11 +2322,12 @@ ${smartTruncate(str, 500)}`
|
|
|
2321
2322
|
function escapePango(text) {
|
|
2322
2323
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
2323
2324
|
}
|
|
2324
|
-
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1) {
|
|
2325
|
+
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
2325
2326
|
const lines = [];
|
|
2326
2327
|
if (locked) lines.push("\u26A0\uFE0F LOCKED BY ADMIN POLICY\n");
|
|
2327
2328
|
lines.push(`\u{1F916} ${agent || "AI Agent"} | \u{1F527} ${toolName}`);
|
|
2328
2329
|
lines.push(`\u{1F6E1}\uFE0F ${explainableLabel || "Security Policy"}`);
|
|
2330
|
+
if (ruleDescription) lines.push(`\u2139 ${ruleDescription}`);
|
|
2329
2331
|
lines.push("");
|
|
2330
2332
|
lines.push(formattedArgs);
|
|
2331
2333
|
if (allowCount >= 3) {
|
|
@@ -2338,7 +2340,7 @@ function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
2338
2340
|
}
|
|
2339
2341
|
return lines.join("\n");
|
|
2340
2342
|
}
|
|
2341
|
-
function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1) {
|
|
2343
|
+
function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
2342
2344
|
const lines = [];
|
|
2343
2345
|
if (locked) {
|
|
2344
2346
|
lines.push('<span foreground="red" weight="bold">\u26A0\uFE0F LOCKED BY ADMIN POLICY</span>');
|
|
@@ -2348,6 +2350,7 @@ function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
2348
2350
|
`<b>\u{1F916} ${escapePango(agent || "AI Agent")}</b> | <b>\u{1F527} <tt>${escapePango(toolName)}</tt></b>`
|
|
2349
2351
|
);
|
|
2350
2352
|
lines.push(`<i>\u{1F6E1}\uFE0F ${escapePango(explainableLabel || "Security Policy")}</i>`);
|
|
2353
|
+
if (ruleDescription) lines.push(`<i>\u2139 ${escapePango(ruleDescription)}</i>`);
|
|
2351
2354
|
lines.push("");
|
|
2352
2355
|
lines.push(`<tt>${escapePango(formattedArgs)}</tt>`);
|
|
2353
2356
|
if (allowCount >= 3) {
|
|
@@ -2364,7 +2367,7 @@ function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
2364
2367
|
}
|
|
2365
2368
|
return lines.join("\n");
|
|
2366
2369
|
}
|
|
2367
|
-
async function askNativePopup(toolName, args, agent, explainableLabel, locked = false, signal, matchedField, matchedWord, allowCount = 1) {
|
|
2370
|
+
async function askNativePopup(toolName, args, agent, explainableLabel, locked = false, signal, matchedField, matchedWord, allowCount = 1, ruleDescription) {
|
|
2368
2371
|
if (isTestEnv()) return "deny";
|
|
2369
2372
|
const { message: formattedArgs, intent } = formatArgs(args, matchedField, matchedWord);
|
|
2370
2373
|
const intentLabel = intent === "EDIT" ? "Code Edit" : "Action Approval";
|
|
@@ -2375,7 +2378,8 @@ async function askNativePopup(toolName, args, agent, explainableLabel, locked =
|
|
|
2375
2378
|
agent,
|
|
2376
2379
|
explainableLabel,
|
|
2377
2380
|
locked,
|
|
2378
|
-
allowCount
|
|
2381
|
+
allowCount,
|
|
2382
|
+
ruleDescription
|
|
2379
2383
|
);
|
|
2380
2384
|
return new Promise((resolve) => {
|
|
2381
2385
|
let childProcess = null;
|
|
@@ -2409,7 +2413,8 @@ end run`;
|
|
|
2409
2413
|
agent,
|
|
2410
2414
|
explainableLabel,
|
|
2411
2415
|
locked,
|
|
2412
|
-
allowCount
|
|
2416
|
+
allowCount,
|
|
2417
|
+
ruleDescription
|
|
2413
2418
|
);
|
|
2414
2419
|
const argsList = [
|
|
2415
2420
|
locked ? "--info" : "--question",
|
|
@@ -2477,7 +2482,7 @@ function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
|
|
|
2477
2482
|
}).catch(() => {
|
|
2478
2483
|
});
|
|
2479
2484
|
}
|
|
2480
|
-
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata) {
|
|
2485
|
+
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPolicy, forceReview) {
|
|
2481
2486
|
const controller = new AbortController();
|
|
2482
2487
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
2483
2488
|
if (!creds.apiKey) throw new Error("Node9 API Key is missing");
|
|
@@ -2522,7 +2527,9 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata) {
|
|
|
2522
2527
|
platform: import_os8.default.platform()
|
|
2523
2528
|
},
|
|
2524
2529
|
...riskMetadata && { riskMetadata },
|
|
2525
|
-
...ciContext && { ciContext }
|
|
2530
|
+
...ciContext && { ciContext },
|
|
2531
|
+
...agentPolicy && { policy: agentPolicy },
|
|
2532
|
+
...forceReview && { forceReview: true }
|
|
2526
2533
|
}),
|
|
2527
2534
|
signal: controller.signal
|
|
2528
2535
|
});
|
|
@@ -2914,6 +2921,7 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2914
2921
|
policyMatchedWord,
|
|
2915
2922
|
policyResult.ruleName
|
|
2916
2923
|
);
|
|
2924
|
+
if (policyRuleDescription) riskMetadata.ruleDescription = policyRuleDescription.slice(0, 200);
|
|
2917
2925
|
const persistent = policyResult.ruleName ? null : getPersistentDecision(toolName);
|
|
2918
2926
|
if (persistent === "allow") {
|
|
2919
2927
|
if (approvers.cloud && creds?.apiKey)
|
|
@@ -2948,9 +2956,18 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2948
2956
|
}
|
|
2949
2957
|
let cloudRequestId = null;
|
|
2950
2958
|
const cloudEnforced = approvers.cloud && !!creds?.apiKey;
|
|
2951
|
-
|
|
2959
|
+
const forceReview = localSmartRuleMatched === true || options?.localSmartRuleMatched === true || void 0;
|
|
2960
|
+
if (cloudEnforced) {
|
|
2952
2961
|
try {
|
|
2953
|
-
const initResult = await initNode9SaaS(
|
|
2962
|
+
const initResult = await initNode9SaaS(
|
|
2963
|
+
toolName,
|
|
2964
|
+
args,
|
|
2965
|
+
creds,
|
|
2966
|
+
meta,
|
|
2967
|
+
riskMetadata,
|
|
2968
|
+
config.settings.agentPolicy,
|
|
2969
|
+
forceReview
|
|
2970
|
+
);
|
|
2954
2971
|
if (!initResult.pending) {
|
|
2955
2972
|
if (initResult.shadowMode) {
|
|
2956
2973
|
return { approved: true, checkedBy: "cloud" };
|
|
@@ -2965,9 +2982,7 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2965
2982
|
};
|
|
2966
2983
|
}
|
|
2967
2984
|
}
|
|
2968
|
-
if (
|
|
2969
|
-
cloudRequestId = initResult.requestId || null;
|
|
2970
|
-
}
|
|
2985
|
+
if (initResult.pending) cloudRequestId = initResult.requestId || null;
|
|
2971
2986
|
if (!taintWarning) explainableLabel = "Organization Policy (SaaS)";
|
|
2972
2987
|
} catch {
|
|
2973
2988
|
}
|
|
@@ -3024,7 +3039,7 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
3024
3039
|
}
|
|
3025
3040
|
}
|
|
3026
3041
|
}
|
|
3027
|
-
if (cloudEnforced && cloudRequestId
|
|
3042
|
+
if (cloudEnforced && cloudRequestId) {
|
|
3028
3043
|
racePromises.push(
|
|
3029
3044
|
(async () => {
|
|
3030
3045
|
try {
|
|
@@ -3056,7 +3071,8 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
3056
3071
|
signal,
|
|
3057
3072
|
policyMatchedField,
|
|
3058
3073
|
policyMatchedWord,
|
|
3059
|
-
daemonAllowCount
|
|
3074
|
+
daemonAllowCount,
|
|
3075
|
+
riskMetadata?.ruleDescription
|
|
3060
3076
|
);
|
|
3061
3077
|
if (decision === "always_allow") {
|
|
3062
3078
|
writeTrustSession(toolName, 36e5);
|
package/dist/index.mjs
CHANGED
|
@@ -208,7 +208,8 @@ var ConfigFileSchema = z.object({
|
|
|
208
208
|
slackEnabled: z.boolean().optional(),
|
|
209
209
|
enableTrustSessions: z.boolean().optional(),
|
|
210
210
|
allowGlobalPause: z.boolean().optional(),
|
|
211
|
-
auditHashArgs: z.boolean().optional()
|
|
211
|
+
auditHashArgs: z.boolean().optional(),
|
|
212
|
+
agentPolicy: z.enum(["require_approval", "block_on_rules"]).optional()
|
|
212
213
|
}).optional(),
|
|
213
214
|
policy: z.object({
|
|
214
215
|
sandboxPaths: z.array(z.string()).optional(),
|
|
@@ -2291,11 +2292,12 @@ ${smartTruncate(str, 500)}`
|
|
|
2291
2292
|
function escapePango(text) {
|
|
2292
2293
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
2293
2294
|
}
|
|
2294
|
-
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1) {
|
|
2295
|
+
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
2295
2296
|
const lines = [];
|
|
2296
2297
|
if (locked) lines.push("\u26A0\uFE0F LOCKED BY ADMIN POLICY\n");
|
|
2297
2298
|
lines.push(`\u{1F916} ${agent || "AI Agent"} | \u{1F527} ${toolName}`);
|
|
2298
2299
|
lines.push(`\u{1F6E1}\uFE0F ${explainableLabel || "Security Policy"}`);
|
|
2300
|
+
if (ruleDescription) lines.push(`\u2139 ${ruleDescription}`);
|
|
2299
2301
|
lines.push("");
|
|
2300
2302
|
lines.push(formattedArgs);
|
|
2301
2303
|
if (allowCount >= 3) {
|
|
@@ -2308,7 +2310,7 @@ function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
2308
2310
|
}
|
|
2309
2311
|
return lines.join("\n");
|
|
2310
2312
|
}
|
|
2311
|
-
function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1) {
|
|
2313
|
+
function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
2312
2314
|
const lines = [];
|
|
2313
2315
|
if (locked) {
|
|
2314
2316
|
lines.push('<span foreground="red" weight="bold">\u26A0\uFE0F LOCKED BY ADMIN POLICY</span>');
|
|
@@ -2318,6 +2320,7 @@ function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
2318
2320
|
`<b>\u{1F916} ${escapePango(agent || "AI Agent")}</b> | <b>\u{1F527} <tt>${escapePango(toolName)}</tt></b>`
|
|
2319
2321
|
);
|
|
2320
2322
|
lines.push(`<i>\u{1F6E1}\uFE0F ${escapePango(explainableLabel || "Security Policy")}</i>`);
|
|
2323
|
+
if (ruleDescription) lines.push(`<i>\u2139 ${escapePango(ruleDescription)}</i>`);
|
|
2321
2324
|
lines.push("");
|
|
2322
2325
|
lines.push(`<tt>${escapePango(formattedArgs)}</tt>`);
|
|
2323
2326
|
if (allowCount >= 3) {
|
|
@@ -2334,7 +2337,7 @@ function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
2334
2337
|
}
|
|
2335
2338
|
return lines.join("\n");
|
|
2336
2339
|
}
|
|
2337
|
-
async function askNativePopup(toolName, args, agent, explainableLabel, locked = false, signal, matchedField, matchedWord, allowCount = 1) {
|
|
2340
|
+
async function askNativePopup(toolName, args, agent, explainableLabel, locked = false, signal, matchedField, matchedWord, allowCount = 1, ruleDescription) {
|
|
2338
2341
|
if (isTestEnv()) return "deny";
|
|
2339
2342
|
const { message: formattedArgs, intent } = formatArgs(args, matchedField, matchedWord);
|
|
2340
2343
|
const intentLabel = intent === "EDIT" ? "Code Edit" : "Action Approval";
|
|
@@ -2345,7 +2348,8 @@ async function askNativePopup(toolName, args, agent, explainableLabel, locked =
|
|
|
2345
2348
|
agent,
|
|
2346
2349
|
explainableLabel,
|
|
2347
2350
|
locked,
|
|
2348
|
-
allowCount
|
|
2351
|
+
allowCount,
|
|
2352
|
+
ruleDescription
|
|
2349
2353
|
);
|
|
2350
2354
|
return new Promise((resolve) => {
|
|
2351
2355
|
let childProcess = null;
|
|
@@ -2379,7 +2383,8 @@ end run`;
|
|
|
2379
2383
|
agent,
|
|
2380
2384
|
explainableLabel,
|
|
2381
2385
|
locked,
|
|
2382
|
-
allowCount
|
|
2386
|
+
allowCount,
|
|
2387
|
+
ruleDescription
|
|
2383
2388
|
);
|
|
2384
2389
|
const argsList = [
|
|
2385
2390
|
locked ? "--info" : "--question",
|
|
@@ -2447,7 +2452,7 @@ function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
|
|
|
2447
2452
|
}).catch(() => {
|
|
2448
2453
|
});
|
|
2449
2454
|
}
|
|
2450
|
-
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata) {
|
|
2455
|
+
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPolicy, forceReview) {
|
|
2451
2456
|
const controller = new AbortController();
|
|
2452
2457
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
2453
2458
|
if (!creds.apiKey) throw new Error("Node9 API Key is missing");
|
|
@@ -2492,7 +2497,9 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata) {
|
|
|
2492
2497
|
platform: os8.platform()
|
|
2493
2498
|
},
|
|
2494
2499
|
...riskMetadata && { riskMetadata },
|
|
2495
|
-
...ciContext && { ciContext }
|
|
2500
|
+
...ciContext && { ciContext },
|
|
2501
|
+
...agentPolicy && { policy: agentPolicy },
|
|
2502
|
+
...forceReview && { forceReview: true }
|
|
2496
2503
|
}),
|
|
2497
2504
|
signal: controller.signal
|
|
2498
2505
|
});
|
|
@@ -2884,6 +2891,7 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2884
2891
|
policyMatchedWord,
|
|
2885
2892
|
policyResult.ruleName
|
|
2886
2893
|
);
|
|
2894
|
+
if (policyRuleDescription) riskMetadata.ruleDescription = policyRuleDescription.slice(0, 200);
|
|
2887
2895
|
const persistent = policyResult.ruleName ? null : getPersistentDecision(toolName);
|
|
2888
2896
|
if (persistent === "allow") {
|
|
2889
2897
|
if (approvers.cloud && creds?.apiKey)
|
|
@@ -2918,9 +2926,18 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2918
2926
|
}
|
|
2919
2927
|
let cloudRequestId = null;
|
|
2920
2928
|
const cloudEnforced = approvers.cloud && !!creds?.apiKey;
|
|
2921
|
-
|
|
2929
|
+
const forceReview = localSmartRuleMatched === true || options?.localSmartRuleMatched === true || void 0;
|
|
2930
|
+
if (cloudEnforced) {
|
|
2922
2931
|
try {
|
|
2923
|
-
const initResult = await initNode9SaaS(
|
|
2932
|
+
const initResult = await initNode9SaaS(
|
|
2933
|
+
toolName,
|
|
2934
|
+
args,
|
|
2935
|
+
creds,
|
|
2936
|
+
meta,
|
|
2937
|
+
riskMetadata,
|
|
2938
|
+
config.settings.agentPolicy,
|
|
2939
|
+
forceReview
|
|
2940
|
+
);
|
|
2924
2941
|
if (!initResult.pending) {
|
|
2925
2942
|
if (initResult.shadowMode) {
|
|
2926
2943
|
return { approved: true, checkedBy: "cloud" };
|
|
@@ -2935,9 +2952,7 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2935
2952
|
};
|
|
2936
2953
|
}
|
|
2937
2954
|
}
|
|
2938
|
-
if (
|
|
2939
|
-
cloudRequestId = initResult.requestId || null;
|
|
2940
|
-
}
|
|
2955
|
+
if (initResult.pending) cloudRequestId = initResult.requestId || null;
|
|
2941
2956
|
if (!taintWarning) explainableLabel = "Organization Policy (SaaS)";
|
|
2942
2957
|
} catch {
|
|
2943
2958
|
}
|
|
@@ -2994,7 +3009,7 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
2994
3009
|
}
|
|
2995
3010
|
}
|
|
2996
3011
|
}
|
|
2997
|
-
if (cloudEnforced && cloudRequestId
|
|
3012
|
+
if (cloudEnforced && cloudRequestId) {
|
|
2998
3013
|
racePromises.push(
|
|
2999
3014
|
(async () => {
|
|
3000
3015
|
try {
|
|
@@ -3026,7 +3041,8 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
3026
3041
|
signal,
|
|
3027
3042
|
policyMatchedField,
|
|
3028
3043
|
policyMatchedWord,
|
|
3029
|
-
daemonAllowCount
|
|
3044
|
+
daemonAllowCount,
|
|
3045
|
+
riskMetadata?.ruleDescription
|
|
3030
3046
|
);
|
|
3031
3047
|
if (decision === "always_allow") {
|
|
3032
3048
|
writeTrustSession(toolName, 36e5);
|