@node9/proxy 1.0.2 → 1.0.4
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 +30 -6
- package/dist/cli.js +748 -63
- package/dist/cli.mjs +748 -63
- package/dist/index.js +32 -5
- package/dist/index.mjs +32 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -350,6 +350,23 @@ function extractShellCommand(toolName, args, toolInspection) {
|
|
|
350
350
|
const value = getNestedValue(args, fieldPath);
|
|
351
351
|
return typeof value === "string" ? value : null;
|
|
352
352
|
}
|
|
353
|
+
function isSqlTool(toolName, toolInspection) {
|
|
354
|
+
const patterns = Object.keys(toolInspection);
|
|
355
|
+
const matchingPattern = patterns.find((p) => matchesPattern(toolName, p));
|
|
356
|
+
if (!matchingPattern) return false;
|
|
357
|
+
const fieldName = toolInspection[matchingPattern];
|
|
358
|
+
return fieldName === "sql" || fieldName === "query";
|
|
359
|
+
}
|
|
360
|
+
var SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
361
|
+
function checkDangerousSql(sql) {
|
|
362
|
+
const norm = sql.replace(/\s+/g, " ").trim().toLowerCase();
|
|
363
|
+
const hasWhere = /\bwhere\b/.test(norm);
|
|
364
|
+
if (/^delete\s+from\s+\S+/.test(norm) && !hasWhere)
|
|
365
|
+
return "DELETE without WHERE \u2014 full table wipe";
|
|
366
|
+
if (/^update\s+\S+\s+set\s+/.test(norm) && !hasWhere)
|
|
367
|
+
return "UPDATE without WHERE \u2014 updates every row";
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
353
370
|
async function analyzeShellCommand(command) {
|
|
354
371
|
const actions = [];
|
|
355
372
|
const paths = [];
|
|
@@ -529,9 +546,20 @@ async function evaluatePolicy(toolName, args, agent) {
|
|
|
529
546
|
if (INLINE_EXEC_PATTERN.test(shellCommand.trim())) {
|
|
530
547
|
return { decision: "review", blockedByLabel: "Node9 Standard (Inline Execution)" };
|
|
531
548
|
}
|
|
549
|
+
if (isSqlTool(toolName, config.policy.toolInspection)) {
|
|
550
|
+
const sqlDanger = checkDangerousSql(shellCommand);
|
|
551
|
+
if (sqlDanger) return { decision: "review", blockedByLabel: `SQL Safety: ${sqlDanger}` };
|
|
552
|
+
allTokens = allTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
|
|
553
|
+
actionTokens = actionTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
|
|
554
|
+
}
|
|
532
555
|
} else {
|
|
533
556
|
allTokens = tokenize(toolName);
|
|
534
557
|
actionTokens = [toolName];
|
|
558
|
+
if (args && typeof args === "object") {
|
|
559
|
+
const flattenedArgs = JSON.stringify(args).toLowerCase();
|
|
560
|
+
const extraTokens = flattenedArgs.split(/[^a-zA-Z0-9]+/).filter((t) => t.length > 1);
|
|
561
|
+
allTokens.push(...extraTokens);
|
|
562
|
+
}
|
|
535
563
|
}
|
|
536
564
|
const isManual = agent === "Terminal";
|
|
537
565
|
if (isManual) {
|
|
@@ -760,8 +788,7 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
760
788
|
const cloudEnforced = approvers.cloud && !!creds?.apiKey;
|
|
761
789
|
if (cloudEnforced) {
|
|
762
790
|
try {
|
|
763
|
-
const
|
|
764
|
-
const initResult = await initNode9SaaS(toolName, args, creds, envConfig?.slackChannel, meta);
|
|
791
|
+
const initResult = await initNode9SaaS(toolName, args, creds, meta);
|
|
765
792
|
if (!initResult.pending) {
|
|
766
793
|
return {
|
|
767
794
|
approved: !!initResult.approved,
|
|
@@ -1015,6 +1042,7 @@ function getConfig() {
|
|
|
1015
1042
|
if (s.enableHookLogDebug !== void 0)
|
|
1016
1043
|
mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
|
|
1017
1044
|
if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
|
|
1045
|
+
if (s.environment !== void 0) mergedSettings.environment = s.environment;
|
|
1018
1046
|
if (p.sandboxPaths) mergedPolicy.sandboxPaths.push(...p.sandboxPaths);
|
|
1019
1047
|
if (p.ignoredTools) mergedPolicy.ignoredTools.push(...p.ignoredTools);
|
|
1020
1048
|
if (p.dangerousWords) mergedPolicy.dangerousWords = [...p.dangerousWords];
|
|
@@ -1044,7 +1072,7 @@ function tryLoadConfig(filePath) {
|
|
|
1044
1072
|
}
|
|
1045
1073
|
}
|
|
1046
1074
|
function getActiveEnvironment(config) {
|
|
1047
|
-
const env = process.env.NODE_ENV || "development";
|
|
1075
|
+
const env = config.settings.environment || process.env.NODE_ENV || "development";
|
|
1048
1076
|
return config.environments[env] ?? null;
|
|
1049
1077
|
}
|
|
1050
1078
|
function getCredentials() {
|
|
@@ -1104,7 +1132,7 @@ function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
|
|
|
1104
1132
|
}).catch(() => {
|
|
1105
1133
|
});
|
|
1106
1134
|
}
|
|
1107
|
-
async function initNode9SaaS(toolName, args, creds,
|
|
1135
|
+
async function initNode9SaaS(toolName, args, creds, meta) {
|
|
1108
1136
|
const controller = new AbortController();
|
|
1109
1137
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
1110
1138
|
try {
|
|
@@ -1114,7 +1142,6 @@ async function initNode9SaaS(toolName, args, creds, slackChannel, meta) {
|
|
|
1114
1142
|
body: JSON.stringify({
|
|
1115
1143
|
toolName,
|
|
1116
1144
|
args,
|
|
1117
|
-
slackChannel,
|
|
1118
1145
|
context: {
|
|
1119
1146
|
agent: meta?.agent,
|
|
1120
1147
|
mcpServer: meta?.mcpServer,
|
package/dist/index.mjs
CHANGED
|
@@ -314,6 +314,23 @@ function extractShellCommand(toolName, args, toolInspection) {
|
|
|
314
314
|
const value = getNestedValue(args, fieldPath);
|
|
315
315
|
return typeof value === "string" ? value : null;
|
|
316
316
|
}
|
|
317
|
+
function isSqlTool(toolName, toolInspection) {
|
|
318
|
+
const patterns = Object.keys(toolInspection);
|
|
319
|
+
const matchingPattern = patterns.find((p) => matchesPattern(toolName, p));
|
|
320
|
+
if (!matchingPattern) return false;
|
|
321
|
+
const fieldName = toolInspection[matchingPattern];
|
|
322
|
+
return fieldName === "sql" || fieldName === "query";
|
|
323
|
+
}
|
|
324
|
+
var SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
325
|
+
function checkDangerousSql(sql) {
|
|
326
|
+
const norm = sql.replace(/\s+/g, " ").trim().toLowerCase();
|
|
327
|
+
const hasWhere = /\bwhere\b/.test(norm);
|
|
328
|
+
if (/^delete\s+from\s+\S+/.test(norm) && !hasWhere)
|
|
329
|
+
return "DELETE without WHERE \u2014 full table wipe";
|
|
330
|
+
if (/^update\s+\S+\s+set\s+/.test(norm) && !hasWhere)
|
|
331
|
+
return "UPDATE without WHERE \u2014 updates every row";
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
317
334
|
async function analyzeShellCommand(command) {
|
|
318
335
|
const actions = [];
|
|
319
336
|
const paths = [];
|
|
@@ -493,9 +510,20 @@ async function evaluatePolicy(toolName, args, agent) {
|
|
|
493
510
|
if (INLINE_EXEC_PATTERN.test(shellCommand.trim())) {
|
|
494
511
|
return { decision: "review", blockedByLabel: "Node9 Standard (Inline Execution)" };
|
|
495
512
|
}
|
|
513
|
+
if (isSqlTool(toolName, config.policy.toolInspection)) {
|
|
514
|
+
const sqlDanger = checkDangerousSql(shellCommand);
|
|
515
|
+
if (sqlDanger) return { decision: "review", blockedByLabel: `SQL Safety: ${sqlDanger}` };
|
|
516
|
+
allTokens = allTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
|
|
517
|
+
actionTokens = actionTokens.filter((t) => !SQL_DML_KEYWORDS.has(t.toLowerCase()));
|
|
518
|
+
}
|
|
496
519
|
} else {
|
|
497
520
|
allTokens = tokenize(toolName);
|
|
498
521
|
actionTokens = [toolName];
|
|
522
|
+
if (args && typeof args === "object") {
|
|
523
|
+
const flattenedArgs = JSON.stringify(args).toLowerCase();
|
|
524
|
+
const extraTokens = flattenedArgs.split(/[^a-zA-Z0-9]+/).filter((t) => t.length > 1);
|
|
525
|
+
allTokens.push(...extraTokens);
|
|
526
|
+
}
|
|
499
527
|
}
|
|
500
528
|
const isManual = agent === "Terminal";
|
|
501
529
|
if (isManual) {
|
|
@@ -724,8 +752,7 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
724
752
|
const cloudEnforced = approvers.cloud && !!creds?.apiKey;
|
|
725
753
|
if (cloudEnforced) {
|
|
726
754
|
try {
|
|
727
|
-
const
|
|
728
|
-
const initResult = await initNode9SaaS(toolName, args, creds, envConfig?.slackChannel, meta);
|
|
755
|
+
const initResult = await initNode9SaaS(toolName, args, creds, meta);
|
|
729
756
|
if (!initResult.pending) {
|
|
730
757
|
return {
|
|
731
758
|
approved: !!initResult.approved,
|
|
@@ -979,6 +1006,7 @@ function getConfig() {
|
|
|
979
1006
|
if (s.enableHookLogDebug !== void 0)
|
|
980
1007
|
mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
|
|
981
1008
|
if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
|
|
1009
|
+
if (s.environment !== void 0) mergedSettings.environment = s.environment;
|
|
982
1010
|
if (p.sandboxPaths) mergedPolicy.sandboxPaths.push(...p.sandboxPaths);
|
|
983
1011
|
if (p.ignoredTools) mergedPolicy.ignoredTools.push(...p.ignoredTools);
|
|
984
1012
|
if (p.dangerousWords) mergedPolicy.dangerousWords = [...p.dangerousWords];
|
|
@@ -1008,7 +1036,7 @@ function tryLoadConfig(filePath) {
|
|
|
1008
1036
|
}
|
|
1009
1037
|
}
|
|
1010
1038
|
function getActiveEnvironment(config) {
|
|
1011
|
-
const env = process.env.NODE_ENV || "development";
|
|
1039
|
+
const env = config.settings.environment || process.env.NODE_ENV || "development";
|
|
1012
1040
|
return config.environments[env] ?? null;
|
|
1013
1041
|
}
|
|
1014
1042
|
function getCredentials() {
|
|
@@ -1068,7 +1096,7 @@ function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
|
|
|
1068
1096
|
}).catch(() => {
|
|
1069
1097
|
});
|
|
1070
1098
|
}
|
|
1071
|
-
async function initNode9SaaS(toolName, args, creds,
|
|
1099
|
+
async function initNode9SaaS(toolName, args, creds, meta) {
|
|
1072
1100
|
const controller = new AbortController();
|
|
1073
1101
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
1074
1102
|
try {
|
|
@@ -1078,7 +1106,6 @@ async function initNode9SaaS(toolName, args, creds, slackChannel, meta) {
|
|
|
1078
1106
|
body: JSON.stringify({
|
|
1079
1107
|
toolName,
|
|
1080
1108
|
args,
|
|
1081
|
-
slackChannel,
|
|
1082
1109
|
context: {
|
|
1083
1110
|
agent: meta?.agent,
|
|
1084
1111
|
mcpServer: meta?.mcpServer,
|