@lazyingart/agintiflow 0.20.236 → 0.20.237
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/package.json +1 -1
- package/scripts/smoke-tmux-tools.js +20 -0
- package/src/guardrails.js +44 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.237",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -261,6 +261,24 @@ try {
|
|
|
261
261
|
assert.equal(dockerNestedAginti.allowed, false, "Docker run_command should block nested aginti CLI calls");
|
|
262
262
|
assert.equal(dockerNestedAginti.category, "nested-aginti", "nested aginti block should be categorized");
|
|
263
263
|
|
|
264
|
+
const dockerShellNestedAginti = checkToolUse({
|
|
265
|
+
toolName: "run_command",
|
|
266
|
+
args: { command: "bash -lc 'aginti doctor --json'" },
|
|
267
|
+
config: dockerConfig,
|
|
268
|
+
});
|
|
269
|
+
assert.equal(dockerShellNestedAginti.allowed, false, "Docker shell -c should not bypass the nested aginti guard");
|
|
270
|
+
assert.equal(dockerShellNestedAginti.category, "nested-aginti", "shell-nested aginti block should be categorized");
|
|
271
|
+
|
|
272
|
+
const dockerAgintiLiteral = checkToolUse({
|
|
273
|
+
toolName: "run_command",
|
|
274
|
+
args: {
|
|
275
|
+
command:
|
|
276
|
+
"/aginti-env/python/bin/python3 -c \"import docx; print('aginti has all')\"; cat /aginti-env/python/pyvenv.cfg",
|
|
277
|
+
},
|
|
278
|
+
config: dockerConfig,
|
|
279
|
+
});
|
|
280
|
+
assert.equal(dockerAgintiLiteral.allowed, true, "AgInTi text and /aginti-env paths must not be treated as nested CLI calls");
|
|
281
|
+
|
|
264
282
|
console.log(
|
|
265
283
|
JSON.stringify(
|
|
266
284
|
{
|
|
@@ -291,6 +309,8 @@ try {
|
|
|
291
309
|
"docker-run-command-tmux-search-allowed",
|
|
292
310
|
"docker-run-command-npx-aginti-guardrail",
|
|
293
311
|
"docker-run-command-nested-aginti-guardrail",
|
|
312
|
+
"docker-run-command-shell-nested-aginti-guardrail",
|
|
313
|
+
"docker-run-command-aginti-literal-and-env-path",
|
|
294
314
|
],
|
|
295
315
|
},
|
|
296
316
|
null,
|
package/src/guardrails.js
CHANGED
|
@@ -7,6 +7,7 @@ import { checkMcpToolUse, isMcpBridgeTool } from "./mcp/policy.js";
|
|
|
7
7
|
import { AGENTLINK_TOOL_NAMES, checkAgentLinkToolUse } from "./agentlink.js";
|
|
8
8
|
import { normalizeProviderId } from "./provider-contract.js";
|
|
9
9
|
import { resolveAuxiliaryImageEndpoint } from "./auxiliary-tools.js";
|
|
10
|
+
import { splitTopLevelShellCommands, tokenizeShellWords } from "./shell-syntax.js";
|
|
10
11
|
|
|
11
12
|
const DESTRUCTIVE_KEYWORDS = [
|
|
12
13
|
"delete",
|
|
@@ -80,7 +81,49 @@ function isNpxAgintiCommand(command = "") {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
function isAgintiCliCommand(command = "") {
|
|
83
|
-
|
|
84
|
+
const executableIndex = (tokens = []) => {
|
|
85
|
+
let index = 0;
|
|
86
|
+
const assignment = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
87
|
+
while (assignment.test(tokens[index] || "")) index += 1;
|
|
88
|
+
|
|
89
|
+
if (pathBase(tokens[index]) === "env") {
|
|
90
|
+
index += 1;
|
|
91
|
+
while (/^-/.test(tokens[index] || "") || assignment.test(tokens[index] || "")) index += 1;
|
|
92
|
+
}
|
|
93
|
+
while (["command", "exec", "nohup", "sudo"].includes(pathBase(tokens[index]))) {
|
|
94
|
+
index += 1;
|
|
95
|
+
while (/^-/.test(tokens[index] || "")) index += 1;
|
|
96
|
+
}
|
|
97
|
+
return index;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const inspect = (source = "", depth = 0) => {
|
|
101
|
+
if (depth > 2) return false;
|
|
102
|
+
for (const segment of splitTopLevelShellCommands(source)) {
|
|
103
|
+
const tokens = tokenizeShellWords(segment);
|
|
104
|
+
if (!tokens.length) continue;
|
|
105
|
+
const index = executableIndex(tokens);
|
|
106
|
+
const executable = pathBase(tokens[index]);
|
|
107
|
+
if (/^aginti(?:\.exe)?$/i.test(executable)) return true;
|
|
108
|
+
if (/^node(?:\.exe)?$/i.test(executable)) {
|
|
109
|
+
const script = tokens.slice(index + 1).find((token) => !token.startsWith("-"));
|
|
110
|
+
if (/^aginti-cli\.js$/i.test(pathBase(script))) return true;
|
|
111
|
+
}
|
|
112
|
+
if (/^(?:ba|z)?sh$/i.test(executable)) {
|
|
113
|
+
const commandOption = tokens.findIndex(
|
|
114
|
+
(token, tokenIndex) => tokenIndex > index && /^-[^-]*c[^-]*$/.test(token)
|
|
115
|
+
);
|
|
116
|
+
if (commandOption >= 0 && inspect(tokens[commandOption + 1] || "", depth + 1)) return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return inspect(command);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function pathBase(value = "") {
|
|
126
|
+
return String(value || "").replace(/\\/g, "/").split("/").at(-1)?.toLowerCase() || "";
|
|
84
127
|
}
|
|
85
128
|
|
|
86
129
|
function normalizeDomain(hostname) {
|