chore(shell): fix ruff F401/F841 + apply ruff format

Pre-existing ruff errors surfaced during Wave 4 QC:
- F401: drop unused `TerminalSession` import (only `TerminalSessionManager` is used)
- F841: drop unused `start = time.monotonic()` local in `_execute_standalone`

`ruff format` then reformatted a few long lines in the same file
(frozenset literal, curl exfiltration regex, pipe operators, session.env
call). No behavior change — formatting only.

Why now: shell.py was already touched by U1 (widen
`bash_command_filter`). Leaving known ruff failures in a file this PR
modifies would make future CI gates noisy.
This commit is contained in:
chiguyong 2026-06-30 11:52:51 +08:00
parent 0a8f6eebef
commit cbbe937940
1 changed files with 26 additions and 13 deletions

View File

@ -18,7 +18,7 @@ from typing import Any, Callable, Awaitable
from agentkit.tools.base import Tool
from agentkit.tools.output_parser import OutputParser, ParsedOutput
from agentkit.tools.terminal_session import TerminalSession, TerminalSessionManager
from agentkit.tools.terminal_session import TerminalSessionManager
from agentkit.tools.pty_session import PTYSession
logger = logging.getLogger(__name__)
@ -159,10 +159,22 @@ _SAFE_COMMAND_PREFIXES: tuple[str, ...] = (
# 危险命令检测 — 基于精确 token 匹配,避免子串误判
# 总是危险的二进制命令(无论参数)
_DANGEROUS_BINARIES: frozenset[str] = frozenset({
"rm", "rmdir", "mkfs", "dd", "format", "shutdown", "reboot",
"halt", "killall", "chown", "fdisk", "parted",
})
_DANGEROUS_BINARIES: frozenset[str] = frozenset(
{
"rm",
"rmdir",
"mkfs",
"dd",
"format",
"shutdown",
"reboot",
"halt",
"killall",
"chown",
"fdisk",
"parted",
}
)
# 需要特定参数才危险的二进制命令binary → 危险 flag/子命令集合
_DANGEROUS_BINARY_FLAGS: dict[str, set[str]] = {
@ -183,13 +195,16 @@ _DANGEROUS_ARG_PATTERNS: list[re.Pattern[str]] = [
re.compile(r"drop\s+database", re.IGNORECASE),
re.compile(r"truncate\s+table", re.IGNORECASE),
# curl/wget data exfiltration: POST/PUT/upload flags
re.compile(r"\bcurl\b.*(-X\s*(POST|PUT|PATCH|DELETE)|--data|--data-binary|--data-raw|--data-urlencode|-d\s|--post\d)", re.IGNORECASE),
re.compile(
r"\bcurl\b.*(-X\s*(POST|PUT|PATCH|DELETE)|--data|--data-binary|--data-raw|--data-urlencode|-d\s|--post\d)",
re.IGNORECASE,
),
re.compile(r"\bwget\b.*(--post-data|--post-file)", re.IGNORECASE),
]
_SHELL_PIPE_OPERATORS = re.compile(r'\|')
_SHELL_CHAIN_OPERATORS = re.compile(r'[;&]|\|\||&&|\$\(|\$\{|`|\$<|>|<|\n')
_SHELL_PIPE_OPERATORS = re.compile(r"\|")
_SHELL_CHAIN_OPERATORS = re.compile(r"[;&]|\|\||&&|\$\(|\$\{|`|\$<|>|<|\n")
class ShellTool(Tool):
@ -360,6 +375,7 @@ class ShellTool(Tool):
# Ensure non-empty output for successful commands (all execution modes)
if result.exit_code == 0 and not output.strip():
from agentkit.core.fallback import SHELL_NO_OUTPUT
output = SHELL_NO_OUTPUT
return {
@ -383,7 +399,6 @@ class ShellTool(Tool):
if interactive:
return await self._execute_with_pty(command, timeout, working_dir)
start = time.monotonic()
try:
proc = await asyncio.create_subprocess_shell(
command,
@ -430,9 +445,7 @@ class ShellTool(Tool):
)
if interactive:
return await self._execute_with_pty(
command, timeout, session.cwd, session.env
)
return await self._execute_with_pty(command, timeout, session.cwd, session.env)
return await session.execute(command, timeout=timeout)
@ -482,7 +495,7 @@ class ShellTool(Tool):
# Handle pipe commands: split and check each sub-command
if _SHELL_PIPE_OPERATORS.search(command_stripped):
parts = command_stripped.split('|')
parts = command_stripped.split("|")
for part in parts:
part = part.strip()
if not part: